Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d51a7fa

Browse files
author
Nikita Glukhov
committed
Allow variable jsonpath specifications
1 parent 3f06a86 commit d51a7fa

File tree

10 files changed

+72
-25
lines changed

10 files changed

+72
-25
lines changed

src/backend/executor/execExpr.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,6 +2050,13 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
20502050
&scratch.d.jsonexpr.raw_expr->value,
20512051
&scratch.d.jsonexpr.raw_expr->isnull);
20522052

2053+
scratch.d.jsonexpr.pathspec =
2054+
palloc(sizeof(*scratch.d.jsonexpr.pathspec));
2055+
2056+
ExecInitExprRec((Expr *) jexpr->path_spec, parent, state,
2057+
&scratch.d.jsonexpr.pathspec->value,
2058+
&scratch.d.jsonexpr.pathspec->isnull);
2059+
20532060
scratch.d.jsonexpr.formatted_expr =
20542061
ExecInitExpr((Expr *) jexpr->formatted_expr, parent);
20552062

src/backend/executor/execExprInterp.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3946,16 +3946,15 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39463946
*op->resnull = true; /* until we get a result */
39473947
*op->resvalue = (Datum) 0;
39483948

3949-
if (op->d.jsonexpr.raw_expr->isnull)
3949+
if (op->d.jsonexpr.raw_expr->isnull || op->d.jsonexpr.pathspec->isnull)
39503950
{
39513951
/* execute domain checks for NULLs */
39523952
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull, isjsonb);
39533953
return;
39543954
}
39553955

39563956
item = op->d.jsonexpr.raw_expr->value;
3957-
3958-
path = DatumGetJsonPathP(jexpr->path_spec->constvalue);
3957+
path = DatumGetJsonPathP(op->d.jsonexpr.pathspec->value);
39593958

39603959
/* reset JSON path variable contexts */
39613960
foreach(lc, op->d.jsonexpr.args)

src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2331,7 +2331,7 @@ _copyJsonCommon(const JsonCommon *from)
23312331
JsonCommon *newnode = makeNode(JsonCommon);
23322332

23332333
COPY_NODE_FIELD(expr);
2334-
COPY_STRING_FIELD(pathspec);
2334+
COPY_NODE_FIELD(pathspec);
23352335
COPY_STRING_FIELD(pathname);
23362336
COPY_NODE_FIELD(passing);
23372337
COPY_LOCATION_FIELD(location);

src/backend/parser/gram.y

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
626626
json_table_plan_cross
627627
json_table_plan_primary
628628
json_table_default_plan
629+
json_path_specification
629630

630631
%type <list> json_arguments
631632
json_passing_clause_opt
@@ -637,8 +638,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
637638

638639
%type <typnam> json_returning_clause_opt
639640

640-
%type <str> json_path_specification
641-
json_table_column_path_specification_clause_opt
641+
%type <str> json_table_column_path_specification_clause_opt
642642
json_table_path_name
643643
json_as_path_name_clause_opt
644644

@@ -847,6 +847,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
847847
*/
848848
%nonassoc UNBOUNDED /* ideally should have same precedence as IDENT */
849849
%nonassoc ERROR_P EMPTY_P DEFAULT ABSENT /* JSON error/empty behavior */
850+
%nonassoc COLUMNS FALSE_P KEEP OMIT PASSING TRUE_P UNKNOWN
850851
%nonassoc IDENT GENERATED NULL_P PARTITION RANGE ROWS PRECEDING FOLLOWING CUBE ROLLUP
851852
%left Op OPERATOR /* multi-character ops and user-defined operators */
852853
%left '+' '-'
@@ -14455,7 +14456,7 @@ json_context_item:
1445514456
;
1445614457

1445714458
json_path_specification:
14458-
Sconst { $$ = $1; }
14459+
a_expr { $$ = $1; }
1445914460
;
1446014461

1446114462
json_as_path_name_clause_opt:
@@ -14753,7 +14754,7 @@ json_table_error_clause_opt:
1475314754
;
1475414755

1475514756
json_table_column_path_specification_clause_opt:
14756-
PATH json_path_specification { $$ = $2; }
14757+
PATH Sconst { $$ = $2; }
1475714758
| /* EMPTY */ %prec json_table_column { $$ = NULL; }
1475814759
;
1475914760

@@ -14785,7 +14786,7 @@ json_table_formatted_column_definition:
1478514786
;
1478614787

1478714788
json_table_nested_columns:
14788-
NESTED path_opt json_path_specification
14789+
NESTED path_opt Sconst
1478914790
json_as_path_name_clause_opt
1479014791
json_table_columns_clause
1479114792
{

src/backend/parser/parse_clause.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,18 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
10591059
return tablesample;
10601060
}
10611061

1062+
static Node *
1063+
makeStringConst(char *str, int location)
1064+
{
1065+
A_Const *n = makeNode(A_Const);
1066+
1067+
n->val.type = T_String;
1068+
n->val.val.str = str;
1069+
n->location = location;
1070+
1071+
return (Node *)n;
1072+
}
1073+
10621074
/*
10631075
* getRTEForSpecialRelationTypes
10641076
*
@@ -1102,6 +1114,7 @@ transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr,
11021114
JsonValueExpr *jvexpr = makeNode(JsonValueExpr);
11031115
JsonCommon *common = makeNode(JsonCommon);
11041116
JsonOutput *output = makeNode(JsonOutput);
1117+
JsonPathSpec pathspec;
11051118

11061119
jfexpr->op = jtc->coltype == JTC_REGULAR ? IS_JSON_VALUE : IS_JSON_QUERY;
11071120
jfexpr->common = common;
@@ -1122,7 +1135,7 @@ transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr,
11221135
common->passing = passingArgs;
11231136

11241137
if (jtc->pathspec)
1125-
common->pathspec = jtc->pathspec;
1138+
pathspec = jtc->pathspec;
11261139
else
11271140
{
11281141
/* Construct default path as '$."column_name"' */
@@ -1133,9 +1146,11 @@ transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr,
11331146
appendStringInfoString(&path, "$.");
11341147
escape_json(&path, jtc->name);
11351148

1136-
common->pathspec = path.data;
1149+
pathspec = path.data;
11371150
}
11381151

1152+
common->pathspec = makeStringConst(pathspec, -1);
1153+
11391154
jvexpr->expr = (Expr *) contextItemExpr;
11401155
jvexpr->format.type = JS_FORMAT_DEFAULT;
11411156
jvexpr->format.encoding = JS_ENC_DEFAULT;
@@ -1629,6 +1644,7 @@ transformJsonTable(ParseState *pstate, JsonTable *jt)
16291644
JsonCommon *jscommon;
16301645
JsonTablePlan *plan = jt->plan;
16311646
char *rootPathName = jt->common->pathname;
1647+
char *rootPath;
16321648
bool is_lateral;
16331649

16341650
cxt.table = jt;
@@ -1658,7 +1674,7 @@ transformJsonTable(ParseState *pstate, JsonTable *jt)
16581674
}
16591675

16601676
jscommon = copyObject(jt->common);
1661-
jscommon->pathspec = pstrdup("$");
1677+
jscommon->pathspec = makeStringConst(pstrdup("$"), -1);
16621678

16631679
jfe->op = IS_JSON_TABLE;
16641680
jfe->common = jscommon;
@@ -1682,10 +1698,19 @@ transformJsonTable(ParseState *pstate, JsonTable *jt)
16821698

16831699
cxt.contextItemTypid = exprType(tf->docexpr);
16841700

1701+
if (!IsA(jt->common->pathspec, A_Const) ||
1702+
castNode(A_Const, jt->common->pathspec)->val.type != T_String)
1703+
ereport(ERROR,
1704+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1705+
errmsg("only string constants supported in JSON_TABLE path specification"),
1706+
parser_errposition(pstate,
1707+
exprLocation(jt->common->pathspec))));
1708+
1709+
rootPath = castNode(A_Const, jt->common->pathspec)->val.val.str;
1710+
16851711
tf->plan = (Node *) transformJsonTableColumns(pstate, &cxt, plan,
16861712
jt->columns,
1687-
jt->common->pathspec,
1688-
&rootPathName,
1713+
rootPath, &rootPathName,
16891714
jt->common->location);
16901715

16911716
tf->ordinalitycol = -1; /* undefine ordinality column number */

src/backend/parser/parse_expr.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4353,7 +4353,7 @@ static JsonExpr *
43534353
transformJsonExprCommon(ParseState *pstate, JsonFuncExpr *func)
43544354
{
43554355
JsonExpr *jsexpr = makeNode(JsonExpr);
4356-
Datum jsonpath;
4356+
Node *pathspec;
43574357
JsonFormatType format;
43584358

43594359
if (func->common->pathname && func->op != IS_JSON_TABLE)
@@ -4383,12 +4383,19 @@ transformJsonExprCommon(ParseState *pstate, JsonFuncExpr *func)
43834383

43844384
jsexpr->format = func->common->expr->format;
43854385

4386-
/* parse JSON path string */
4387-
jsonpath = DirectFunctionCall1(jsonpath_in,
4388-
CStringGetDatum(func->common->pathspec));
4386+
pathspec = transformExprRecurse(pstate, func->common->pathspec);
43894387

4390-
jsexpr->path_spec = makeConst(JSONPATHOID, -1, InvalidOid, -1,
4391-
jsonpath, false, false);
4388+
jsexpr->path_spec =
4389+
coerce_to_target_type(pstate, pathspec, exprType(pathspec),
4390+
JSONPATHOID, -1,
4391+
COERCION_EXPLICIT, COERCE_IMPLICIT_CAST,
4392+
exprLocation(pathspec));
4393+
if (!jsexpr->path_spec)
4394+
ereport(ERROR,
4395+
(errcode(ERRCODE_DATATYPE_MISMATCH),
4396+
errmsg("JSON path expression must be type %s, not type %s",
4397+
"jsonpath", format_type_be(exprType(pathspec))),
4398+
parser_errposition(pstate, exprLocation(pathspec))));
43924399

43934400
/* transform and coerce to json[b] passing arguments */
43944401
transformJsonPassingArgs(pstate, format, func->common->passing,

src/backend/utils/adt/ruleutils.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8837,7 +8837,10 @@ get_rule_expr(Node *node, deparse_context *context,
88378837

88388838
appendStringInfoString(buf, ", ");
88398839

8840-
get_const_expr(jexpr->path_spec, context, -1);
8840+
if (IsA(jexpr->path_spec, Const))
8841+
get_const_expr((Const *) jexpr->path_spec, context, -1);
8842+
else
8843+
get_rule_expr(jexpr->path_spec, context, false);
88418844

88428845
if (jexpr->passing.values)
88438846
{
@@ -9836,7 +9839,11 @@ get_json_table_columns(TableFunc *tf, JsonTableParentNode *node,
98369839
" FORMAT JSONB" : " FORMAT JSON");
98379840

98389841
appendStringInfoString(buf, " PATH ");
9839-
get_const_expr(colexpr->path_spec, context, -1);
9842+
9843+
if (IsA(colexpr->path_spec, Const))
9844+
get_const_expr((Const *) colexpr->path_spec, context, -1);
9845+
else
9846+
get_rule_expr(colexpr->path_spec, context, false);
98409847

98419848
if (colexpr->wrapper == JSW_CONDITIONAL)
98429849
appendStringInfo(buf, " WITH CONDITIONAL WRAPPER");

src/include/executor/execExpr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ typedef struct ExprEvalStep
576576
{
577577
Datum value;
578578
bool isnull;
579-
} *raw_expr; /* raw context item value */
579+
} *raw_expr, /* raw context item value */
580+
*pathspec; /* path specification value */
580581

581582
ExprState *formatted_expr; /* formatted context item */
582583
ExprState *result_expr; /* coerced to output type */

src/include/nodes/parsenodes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1475,7 +1475,7 @@ typedef struct JsonCommon
14751475
{
14761476
NodeTag type;
14771477
JsonValueExpr *expr; /* context item expression */
1478-
JsonPathSpec pathspec; /* JSON path specification */
1478+
Node *pathspec; /* JSON path specification expression */
14791479
char *pathname; /* path name, if any */
14801480
List *passing; /* list of PASSING clause arguments, if any */
14811481
int location; /* token location, or -1 if unknown */

src/include/nodes/primnodes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,7 @@ typedef struct JsonExpr
12881288
bool coerce_via_io; /* coerce result using type input function */
12891289
Oid coerce_via_io_collation; /* collation for conversion through I/O */
12901290
JsonFormat format; /* context item format (JSON/JSONB) */
1291-
Const *path_spec; /* JSON path specification */
1291+
Node *path_spec; /* JSON path specification expression */
12921292
JsonPassing passing; /* PASSING clause arguments */
12931293
JsonReturning returning; /* RETURNING clause type/format info */
12941294
JsonBehavior on_empty; /* ON EMPTY behavior */

0 commit comments

Comments
 (0)