Skip to content

Commit

Permalink
PLAN clauses for JSON_TABLE
Browse files Browse the repository at this point in the history
These clauses allow the user to specify how data from nested paths are
joined, allowing considerable freedom in shaping the tabular output of
JSON_TABLE.

PLAN DEFAULT allows the user to specify the global strategies when
dealing with sibling or child nested paths. The is often sufficient to
achieve the necessary goal, and is considerably simpler than the full
PLAN clause, which allows the user to specify the strategy to be used
for each named nested path.

Nikita Glukhov

Reviewers have included (in no particular order) Andres Freund, Alexander
Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zhihong Yu,
Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby.

Discussion: https://postgr.es/m/[email protected]
  • Loading branch information
adunstan committed Apr 5, 2022
1 parent e83ebfe commit fadb48b
Show file tree
Hide file tree
Showing 17 changed files with 1,614 additions and 109 deletions.
26 changes: 26 additions & 0 deletions src/backend/nodes/copyfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2696,6 +2696,7 @@ _copyJsonTable(const JsonTable *from)

COPY_NODE_FIELD(common);
COPY_NODE_FIELD(columns);
COPY_NODE_FIELD(plan);
COPY_NODE_FIELD(on_error);
COPY_NODE_FIELD(alias);
COPY_SCALAR_FIELD(location);
Expand All @@ -2715,6 +2716,7 @@ _copyJsonTableColumn(const JsonTableColumn *from)
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(typeName);
COPY_STRING_FIELD(pathspec);
COPY_STRING_FIELD(pathname);
COPY_SCALAR_FIELD(format);
COPY_SCALAR_FIELD(wrapper);
COPY_SCALAR_FIELD(omit_quotes);
Expand All @@ -2726,6 +2728,24 @@ _copyJsonTableColumn(const JsonTableColumn *from)
return newnode;
}

/*
* _copyJsonTablePlan
*/
static JsonTablePlan *
_copyJsonTablePlan(const JsonTablePlan *from)
{
JsonTablePlan *newnode = makeNode(JsonTablePlan);

COPY_SCALAR_FIELD(plan_type);
COPY_SCALAR_FIELD(join_type);
COPY_STRING_FIELD(pathname);
COPY_NODE_FIELD(plan1);
COPY_NODE_FIELD(plan2);
COPY_SCALAR_FIELD(location);

return newnode;
}

/*
* _copyJsonTableParent
*/
Expand All @@ -2735,7 +2755,9 @@ _copyJsonTableParent(const JsonTableParent *from)
JsonTableParent *newnode = makeNode(JsonTableParent);

COPY_NODE_FIELD(path);
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(child);
COPY_SCALAR_FIELD(outerJoin);
COPY_SCALAR_FIELD(colMin);
COPY_SCALAR_FIELD(colMax);

Expand All @@ -2752,6 +2774,7 @@ _copyJsonTableSibling(const JsonTableSibling *from)

COPY_NODE_FIELD(larg);
COPY_NODE_FIELD(rarg);
COPY_SCALAR_FIELD(cross);

return newnode;
}
Expand Down Expand Up @@ -5929,6 +5952,9 @@ copyObjectImpl(const void *from)
case T_JsonTableColumn:
retval = _copyJsonTableColumn(from);
break;
case T_JsonTablePlan:
retval = _copyJsonTablePlan(from);
break;
case T_JsonTableParent:
retval = _copyJsonTableParent(from);
break;
Expand Down
3 changes: 3 additions & 0 deletions src/backend/nodes/equalfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ static bool
_equalJsonTableParent(const JsonTableParent *a, const JsonTableParent *b)
{
COMPARE_NODE_FIELD(path);
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(child);
COMPARE_SCALAR_FIELD(outerJoin);
COMPARE_SCALAR_FIELD(colMin);
COMPARE_SCALAR_FIELD(colMax);

Expand All @@ -193,6 +195,7 @@ _equalJsonTableSibling(const JsonTableSibling *a, const JsonTableSibling *b)
{
COMPARE_NODE_FIELD(larg);
COMPARE_NODE_FIELD(rarg);
COMPARE_SCALAR_FIELD(cross);

return true;
}
Expand Down
19 changes: 19 additions & 0 deletions src/backend/nodes/makefuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,25 @@ makeJsonBehavior(JsonBehaviorType type, Node *default_expr)
return behavior;
}

/*
* makeJsonTableJoinedPlan -
* creates a joined JsonTablePlan node
*/
Node *
makeJsonTableJoinedPlan(JsonTablePlanJoinType type, Node *plan1, Node *plan2,
int location)
{
JsonTablePlan *n = makeNode(JsonTablePlan);

n->plan_type = JSTP_JOINED;
n->join_type = type;
n->plan1 = castNode(JsonTablePlan, plan1);
n->plan2 = castNode(JsonTablePlan, plan2);
n->location = location;

return (Node *) n;
}

/*
* makeJsonEncoding -
* converts JSON encoding name to enum JsonEncoding
Expand Down
3 changes: 3 additions & 0 deletions src/backend/nodes/outfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,9 @@ _outJsonTableParent(StringInfo str, const JsonTableParent *node)
WRITE_NODE_TYPE("JSONTABPNODE");

WRITE_NODE_FIELD(path);
WRITE_STRING_FIELD(name);
WRITE_NODE_FIELD(child);
WRITE_BOOL_FIELD(outerJoin);
WRITE_INT_FIELD(colMin);
WRITE_INT_FIELD(colMax);
}
Expand All @@ -1887,6 +1889,7 @@ _outJsonTableSibling(StringInfo str, const JsonTableSibling *node)

WRITE_NODE_FIELD(larg);
WRITE_NODE_FIELD(rarg);
WRITE_BOOL_FIELD(cross);
}

/*****************************************************************************
Expand Down
3 changes: 3 additions & 0 deletions src/backend/nodes/readfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,9 @@ _readJsonTableParent(void)
READ_LOCALS(JsonTableParent);

READ_NODE_FIELD(path);
READ_STRING_FIELD(name);
READ_NODE_FIELD(child);
READ_BOOL_FIELD(outerJoin);
READ_INT_FIELD(colMin);
READ_INT_FIELD(colMax);

Expand All @@ -1555,6 +1557,7 @@ _readJsonTableSibling(void)

READ_NODE_FIELD(larg);
READ_NODE_FIELD(rarg);
READ_BOOL_FIELD(cross);

READ_DONE();
}
Expand Down
130 changes: 126 additions & 4 deletions src/backend/parser/gram.y
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,18 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
json_table_formatted_column_definition
json_table_exists_column_definition
json_table_nested_columns
json_table_plan_clause_opt
json_table_specific_plan
json_table_plan
json_table_plan_simple
json_table_plan_parent_child
json_table_plan_outer
json_table_plan_inner
json_table_plan_sibling
json_table_plan_union
json_table_plan_cross
json_table_plan_primary
json_table_default_plan

%type <list> json_name_and_value_list
json_value_expr_list
Expand All @@ -698,6 +710,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);

%type <ival> json_encoding
json_encoding_clause_opt
json_table_default_plan_choices
json_table_default_plan_inner_outer
json_table_default_plan_union_cross
json_wrapper_clause_opt
json_wrapper_behavior
json_conditional_or_unconditional_opt
Expand Down Expand Up @@ -812,7 +827,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
ORDER ORDINALITY OTHERS OUT_P OUTER_P
OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER

PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PATH PLACING PLANS POLICY
PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PATH PLACING PLAN PLANS POLICY
POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION

Expand Down Expand Up @@ -15928,13 +15943,15 @@ json_table:
JSON_TABLE '('
json_api_common_syntax
json_table_columns_clause
json_table_plan_clause_opt
json_table_error_clause_opt
')'
{
JsonTable *n = makeNode(JsonTable);
n->common = (JsonCommon *) $3;
n->columns = $4;
n->on_error = $5;
n->plan = (JsonTablePlan *) $5;
n->on_error = $6;
n->location = @1;
$$ = (Node *) n;
}
Expand Down Expand Up @@ -16055,12 +16072,15 @@ json_table_formatted_column_definition:
;

json_table_nested_columns:
NESTED path_opt Sconst json_table_columns_clause
NESTED path_opt Sconst
json_as_path_name_clause_opt
json_table_columns_clause
{
JsonTableColumn *n = makeNode(JsonTableColumn);
n->coltype = JTC_NESTED;
n->pathspec = $3;
n->columns = $4;
n->pathname = $4;
n->columns = $5;
n->location = @1;
$$ = (Node *) n;
}
Expand All @@ -16071,6 +16091,106 @@ path_opt:
| /* EMPTY */ { }
;

json_table_plan_clause_opt:
json_table_specific_plan { $$ = $1; }
| json_table_default_plan { $$ = $1; }
| /* EMPTY */ { $$ = NULL; }
;

json_table_specific_plan:
PLAN '(' json_table_plan ')' { $$ = $3; }
;

json_table_plan:
json_table_plan_simple
| json_table_plan_parent_child
| json_table_plan_sibling
;

json_table_plan_simple:
json_table_path_name
{
JsonTablePlan *n = makeNode(JsonTablePlan);
n->plan_type = JSTP_SIMPLE;
n->pathname = $1;
n->location = @1;
$$ = (Node *) n;
}
;

json_table_plan_parent_child:
json_table_plan_outer
| json_table_plan_inner
;

json_table_plan_outer:
json_table_plan_simple OUTER_P json_table_plan_primary
{ $$ = makeJsonTableJoinedPlan(JSTPJ_OUTER, $1, $3, @1); }
;

json_table_plan_inner:
json_table_plan_simple INNER_P json_table_plan_primary
{ $$ = makeJsonTableJoinedPlan(JSTPJ_INNER, $1, $3, @1); }
;

json_table_plan_sibling:
json_table_plan_union
| json_table_plan_cross
;

json_table_plan_union:
json_table_plan_primary UNION json_table_plan_primary
{ $$ = makeJsonTableJoinedPlan(JSTPJ_UNION, $1, $3, @1); }
| json_table_plan_union UNION json_table_plan_primary
{ $$ = makeJsonTableJoinedPlan(JSTPJ_UNION, $1, $3, @1); }
;

json_table_plan_cross:
json_table_plan_primary CROSS json_table_plan_primary
{ $$ = makeJsonTableJoinedPlan(JSTPJ_CROSS, $1, $3, @1); }
| json_table_plan_cross CROSS json_table_plan_primary
{ $$ = makeJsonTableJoinedPlan(JSTPJ_CROSS, $1, $3, @1); }
;

json_table_plan_primary:
json_table_plan_simple { $$ = $1; }
| '(' json_table_plan ')'
{
castNode(JsonTablePlan, $2)->location = @1;
$$ = $2;
}
;

json_table_default_plan:
PLAN DEFAULT '(' json_table_default_plan_choices ')'
{
JsonTablePlan *n = makeNode(JsonTablePlan);
n->plan_type = JSTP_DEFAULT;
n->join_type = $4;
n->location = @1;
$$ = (Node *) n;
}
;

json_table_default_plan_choices:
json_table_default_plan_inner_outer { $$ = $1 | JSTPJ_UNION; }
| json_table_default_plan_inner_outer ','
json_table_default_plan_union_cross { $$ = $1 | $3; }
| json_table_default_plan_union_cross { $$ = $1 | JSTPJ_OUTER; }
| json_table_default_plan_union_cross ','
json_table_default_plan_inner_outer { $$ = $1 | $3; }
;

json_table_default_plan_inner_outer:
INNER_P { $$ = JSTPJ_INNER; }
| OUTER_P { $$ = JSTPJ_OUTER; }
;

json_table_default_plan_union_cross:
UNION { $$ = JSTPJ_UNION; }
| CROSS { $$ = JSTPJ_CROSS; }
;

json_returning_clause_opt:
RETURNING Typename
{
Expand Down Expand Up @@ -16951,6 +17071,7 @@ unreserved_keyword:
| PASSING
| PASSWORD
| PATH
| PLAN
| PLANS
| POLICY
| PRECEDING
Expand Down Expand Up @@ -17568,6 +17689,7 @@ bare_label_keyword:
| PASSWORD
| PATH
| PLACING
| PLAN
| PLANS
| POLICY
| POSITION
Expand Down
Loading

0 comments on commit fadb48b

Please sign in to comment.