PostgreSQL Source Code git master
Loading...
Searching...
No Matches
parse_jsontable.c File Reference
#include "postgres.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_clause.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "utils/fmgrprotos.h"
#include "utils/json.h"
#include "utils/lsyscache.h"
Include dependency graph for parse_jsontable.c:

Go to the source code of this file.

Data Structures

struct  JsonTableParseContext
 

Typedefs

typedef struct JsonTableParseContext JsonTableParseContext
 

Functions

static JsonTablePlantransformJsonTableColumns (JsonTableParseContext *cxt, JsonTablePlanSpec *planspec, List *columns, List *passingArgs, JsonTablePathSpec *pathspec)
 
static JsonTablePlantransformJsonTableNestedColumns (JsonTableParseContext *cxt, JsonTablePlanSpec *plan, List *passingArgs, List *columns)
 
static JsonFuncExprtransformJsonTableColumn (JsonTableColumn *jtc, Node *contextItemExpr, List *passingArgs)
 
static bool isCompositeType (Oid typid)
 
static JsonTablePlanmakeJsonTablePathScan (JsonTableParseContext *cxt, JsonTablePathSpec *pathspec, JsonTablePlanSpec *planspec, bool errorOnError, int colMin, int colMax, JsonTablePlan *childplan)
 
static void CheckDuplicateColumnOrPathNames (JsonTableParseContext *cxt, List *columns)
 
static bool LookupPathOrColumnName (JsonTableParseContext *cxt, char *name)
 
static chargenerateJsonTablePathName (JsonTableParseContext *cxt)
 
static void validateJsonTableChildPlan (JsonTableParseContext *cxt, JsonTablePlanSpec *plan, List *columns)
 
static JsonTablePlanmakeJsonTableSiblingJoin (bool cross, JsonTablePlan *lplan, JsonTablePlan *rplan)
 
static void appendJsonTableColumns (JsonTableParseContext *cxt, List *columns, List *passingArgs)
 
ParseNamespaceItemtransformJsonTable (ParseState *pstate, JsonTable *jt)
 
static JsonTableColumnfindNestedJsonTableColumn (List *columns, const char *pathname)
 
static void collectSiblingPathsInJsonTablePlan (JsonTablePlanSpec *plan, List **paths)
 

Typedef Documentation

◆ JsonTableParseContext

Function Documentation

◆ appendJsonTableColumns()

static void appendJsonTableColumns ( JsonTableParseContext cxt,
List columns,
List passingArgs 
)
static

Definition at line 378 of file parse_jsontable.c.

379{
380 ListCell *col;
381 ParseState *pstate = cxt->pstate;
382 TableFunc *tf = cxt->tf;
383 bool ordinality_found = false;
385
386 foreach(col, columns)
387 {
389 Oid typid;
390 int32 typmod;
392 Node *colexpr;
393
394 if (rawc->name)
395 tf->colnames = lappend(tf->colnames,
396 makeString(pstrdup(rawc->name)));
397
398 /*
399 * Determine the type and typmod for the new column. FOR ORDINALITY
400 * columns are INTEGER by standard; the others are user-specified.
401 */
402 switch (rawc->coltype)
403 {
408 errmsg("only one FOR ORDINALITY column is allowed"),
409 parser_errposition(pstate, rawc->location)));
410 ordinality_found = true;
411 colexpr = NULL;
412 typid = INT4OID;
413 typmod = -1;
414 break;
415
416 case JTC_REGULAR:
417 typenameTypeIdAndMod(pstate, rawc->typeName, &typid, &typmod);
418
419 /*
420 * Use JTC_FORMATTED so as to use JSON_QUERY for this column
421 * if the specified type is one that's better handled using
422 * JSON_QUERY() or if non-default WRAPPER or QUOTES behavior
423 * is specified.
424 */
425 if (isCompositeType(typid) ||
426 rawc->quotes != JS_QUOTES_UNSPEC ||
427 rawc->wrapper != JSW_UNSPEC)
428 rawc->coltype = JTC_FORMATTED;
429
431 case JTC_FORMATTED:
432 case JTC_EXISTS:
433 {
436
437 param->collation = InvalidOid;
438 param->typeId = contextItemTypid;
439 param->typeMod = -1;
440
443
444 colexpr = transformExpr(pstate, (Node *) jfe,
446 assign_expr_collations(pstate, colexpr);
447
448 typid = exprType(colexpr);
449 typmod = exprTypmod(colexpr);
450 typcoll = exprCollation(colexpr);
451 break;
452 }
453
454 case JTC_NESTED:
455 continue;
456
457 default:
458 elog(ERROR, "unknown JSON_TABLE column type: %d", (int) rawc->coltype);
459 break;
460 }
461
462 tf->coltypes = lappend_oid(tf->coltypes, typid);
463 tf->coltypmods = lappend_int(tf->coltypmods, typmod);
464 tf->colcollations = lappend_oid(tf->colcollations, typcoll);
465 tf->colvalexprs = lappend(tf->colvalexprs, colexpr);
466 }
467}
int32_t int32
Definition c.h:679
#define pg_fallthrough
Definition c.h:220
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
List * lappend(List *list, void *datum)
Definition list.c:339
List * lappend_int(List *list, int datum)
Definition list.c:357
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
char * pstrdup(const char *in)
Definition mcxt.c:1910
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826
#define makeNode(_type_)
Definition nodes.h:159
#define castNode(_type_, nodeptr)
Definition nodes.h:180
static char * errmsg
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition parse_expr.c:121
static JsonFuncExpr * transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr, List *passingArgs)
static bool isCompositeType(Oid typid)
int parser_errposition(ParseState *pstate, int location)
Definition parse_node.c:106
@ EXPR_KIND_FROM_FUNCTION
Definition parse_node.h:45
void typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName, Oid *typeid_p, int32 *typmod_p)
Definition parse_type.c:310
@ JTC_FORMATTED
@ JTC_FOR_ORDINALITY
@ JTC_NESTED
@ JTC_EXISTS
@ JTC_REGULAR
@ JS_QUOTES_UNSPEC
#define lfirst(lc)
Definition pg_list.h:172
#define InvalidOid
unsigned int Oid
static int fb(int x)
@ JSW_UNSPEC
Definition primnodes.h:1771
Definition nodes.h:133
Node * docexpr
Definition primnodes.h:121
String * makeString(char *str)
Definition value.c:63

References assign_expr_collations(), castNode, TableFunc::docexpr, elog, ereport, errcode(), errmsg, ERROR, EXPR_KIND_FROM_FUNCTION, exprCollation(), exprType(), exprTypmod(), fb(), InvalidOid, isCompositeType(), JS_QUOTES_UNSPEC, JSW_UNSPEC, JTC_EXISTS, JTC_FOR_ORDINALITY, JTC_FORMATTED, JTC_NESTED, JTC_REGULAR, lappend(), lappend_int(), lappend_oid(), lfirst, makeNode, makeString(), parser_errposition(), pg_fallthrough, JsonTableParseContext::pstate, pstrdup(), JsonTableParseContext::tf, transformExpr(), transformJsonTableColumn(), CaseTestExpr::typeId, and typenameTypeIdAndMod().

Referenced by transformJsonTableColumns().

◆ CheckDuplicateColumnOrPathNames()

static void CheckDuplicateColumnOrPathNames ( JsonTableParseContext cxt,
List columns 
)
static

Definition at line 199 of file parse_jsontable.c.

201{
202 ListCell *lc1;
203
204 foreach(lc1, columns)
205 {
207
208 if (jtc->coltype == JTC_NESTED)
209 {
210 if (jtc->pathspec->name)
211 {
212 if (LookupPathOrColumnName(cxt, jtc->pathspec->name))
215 errmsg("duplicate JSON_TABLE column or path name: %s",
216 jtc->pathspec->name),
218 jtc->pathspec->name_location));
219 cxt->pathNames = lappend(cxt->pathNames, jtc->pathspec->name);
220 }
221
223 }
224 else
225 {
226 if (LookupPathOrColumnName(cxt, jtc->name))
229 errmsg("duplicate JSON_TABLE column or path name: %s",
230 jtc->name),
231 parser_errposition(cxt->pstate, jtc->location));
232 cxt->pathNames = lappend(cxt->pathNames, jtc->name);
233 }
234 }
235}
static bool LookupPathOrColumnName(JsonTableParseContext *cxt, char *name)
static void CheckDuplicateColumnOrPathNames(JsonTableParseContext *cxt, List *columns)

References castNode, CheckDuplicateColumnOrPathNames(), ereport, errcode(), errmsg, ERROR, fb(), JTC_NESTED, lappend(), lfirst, LookupPathOrColumnName(), parser_errposition(), JsonTableParseContext::pathNames, and JsonTableParseContext::pstate.

Referenced by CheckDuplicateColumnOrPathNames(), and transformJsonTable().

◆ collectSiblingPathsInJsonTablePlan()

static void collectSiblingPathsInJsonTablePlan ( JsonTablePlanSpec plan,
List **  paths 
)
static

Definition at line 729 of file parse_jsontable.c.

730{
731 if (plan->plan_type == JSTP_SIMPLE)
732 *paths = lappend(*paths, plan->pathname);
733 else if (plan->plan_type == JSTP_JOINED)
734 {
735 if (plan->join_type == JSTP_JOIN_INNER ||
736 plan->join_type == JSTP_JOIN_OUTER)
737 {
738 Assert(plan->plan1->plan_type == JSTP_SIMPLE);
739 *paths = lappend(*paths, plan->plan1->pathname);
740 }
741 else if (plan->join_type == JSTP_JOIN_CROSS ||
742 plan->join_type == JSTP_JOIN_UNION)
743 {
746 }
747 else
748 elog(ERROR, "invalid JSON_TABLE join type %d",
749 plan->join_type);
750 }
751}
#define Assert(condition)
Definition c.h:1002
static void collectSiblingPathsInJsonTablePlan(JsonTablePlanSpec *plan, List **paths)
@ JSTP_JOINED
@ JSTP_SIMPLE
@ JSTP_JOIN_CROSS
@ JSTP_JOIN_INNER
@ JSTP_JOIN_OUTER
@ JSTP_JOIN_UNION
#define plan(x)
Definition pg_regress.c:164

References Assert, collectSiblingPathsInJsonTablePlan(), elog, ERROR, JSTP_JOIN_CROSS, JSTP_JOIN_INNER, JSTP_JOIN_OUTER, JSTP_JOIN_UNION, JSTP_JOINED, JSTP_SIMPLE, lappend(), and plan.

Referenced by collectSiblingPathsInJsonTablePlan(), and validateJsonTableChildPlan().

◆ findNestedJsonTableColumn()

static JsonTableColumn * findNestedJsonTableColumn ( List columns,
const char pathname 
)
static

Definition at line 547 of file parse_jsontable.c.

548{
549 ListCell *lc;
550
551 foreach(lc, columns)
552 {
554
555 if (jtc->coltype == JTC_NESTED &&
556 jtc->pathspec->name &&
557 !strcmp(jtc->pathspec->name, pathname))
558 return jtc;
559 }
560
561 return NULL;
562}

References castNode, fb(), JTC_NESTED, and lfirst.

Referenced by transformJsonTableNestedColumns().

◆ generateJsonTablePathName()

static char * generateJsonTablePathName ( JsonTableParseContext cxt)
static

Definition at line 257 of file parse_jsontable.c.

258{
259 char namebuf[32];
260 char *name;
261
262 /*
263 * Bump the counter until we produce a name that is not already used as a
264 * path or column name. Otherwise a generated name could coincide with a
265 * user-supplied one, which would confuse PLAN clause matching and could
266 * silently drop a column.
267 */
268 do
269 {
270 snprintf(namebuf, sizeof(namebuf), "json_table_path_%d",
271 cxt->pathNameId++);
272 } while (LookupPathOrColumnName(cxt, namebuf));
273
275 cxt->pathNames = lappend(cxt->pathNames, name);
276
277 return name;
278}
#define snprintf
Definition port.h:261
const char * name

References fb(), lappend(), LookupPathOrColumnName(), name, JsonTableParseContext::pathNameId, JsonTableParseContext::pathNames, pstrdup(), and snprintf.

Referenced by transformJsonTable(), transformJsonTableNestedColumns(), and validateJsonTableChildPlan().

◆ isCompositeType()

static bool isCompositeType ( Oid  typid)
static

Definition at line 474 of file parse_jsontable.c.

475{
476 char typtype = get_typtype(typid);
477
478 return typid == JSONOID ||
479 typid == JSONBOID ||
480 typid == RECORDOID ||
481 type_is_array(typid) ||
482 typtype == TYPTYPE_COMPOSITE ||
483 /* domain over one of the above? */
484 (typtype == TYPTYPE_DOMAIN &&
486}
char get_typtype(Oid typid)
Definition lsyscache.c:2945
Oid getBaseType(Oid typid)
Definition lsyscache.c:2837
#define type_is_array(typid)
Definition lsyscache.h:223

References fb(), get_typtype(), getBaseType(), isCompositeType(), and type_is_array.

Referenced by AlterTypeNamespaceInternal(), appendJsonTableColumns(), and isCompositeType().

◆ LookupPathOrColumnName()

static bool LookupPathOrColumnName ( JsonTableParseContext cxt,
char name 
)
static

Definition at line 242 of file parse_jsontable.c.

243{
244 ListCell *lc;
245
246 foreach(lc, cxt->pathNames)
247 {
248 if (strcmp(name, (const char *) lfirst(lc)) == 0)
249 return true;
250 }
251
252 return false;
253}

References fb(), lfirst, name, and JsonTableParseContext::pathNames.

Referenced by CheckDuplicateColumnOrPathNames(), and generateJsonTablePathName().

◆ makeJsonTablePathScan()

static JsonTablePlan * makeJsonTablePathScan ( JsonTableParseContext cxt,
JsonTablePathSpec pathspec,
JsonTablePlanSpec planspec,
bool  errorOnError,
int  colMin,
int  colMax,
JsonTablePlan childplan 
)
static

Definition at line 673 of file parse_jsontable.c.

678{
680 char *pathstring;
681 Const *value;
682
683 Assert(IsA(pathspec->string, A_Const));
684 pathstring = castNode(A_Const, pathspec->string)->val.sval.sval;
688 false, false);
689
690 scan->plan.type = T_JsonTablePathScan;
691 scan->path = makeJsonTablePath(value, pathspec->name);
692 scan->errorOnError = errorOnError;
693
694 scan->child = childplan;
695
696 scan->colMin = colMin;
697 scan->colMax = colMax;
698
699 if (scan->child)
700 scan->outerJoin = planspec == NULL ||
701 (planspec->join_type & JSTP_JOIN_OUTER);
702 /* else: default plan case, no children found */
703
704 return (JsonTablePlan *) scan;
705}
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:688
static struct @175 value
Datum jsonpath_in(PG_FUNCTION_ARGS)
Definition jsonpath.c:98
JsonTablePath * makeJsonTablePath(Const *pathvalue, char *pathname)
Definition makefuncs.c:1083
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition makefuncs.c:350
#define IsA(nodeptr, _type_)
Definition nodes.h:162
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
JsonTablePath * path
Definition primnodes.h:1919
JsonTablePlan * child
Definition primnodes.h:1928
JsonTablePlan plan
Definition primnodes.h:1916
JsonTablePlanJoinType join_type

References Assert, castNode, JsonTablePathScan::child, JsonTablePathScan::colMax, JsonTablePathScan::colMin, CStringGetDatum(), DirectFunctionCall1, JsonTablePathScan::errorOnError, fb(), InvalidOid, IsA, JsonTablePlanSpec::join_type, jsonpath_in(), JSTP_JOIN_OUTER, makeConst(), makeJsonTablePath(), makeNode, JsonTablePathSpec::name, JsonTablePathScan::outerJoin, JsonTablePathScan::path, JsonTablePathScan::plan, JsonTablePathSpec::string, and value.

Referenced by transformJsonTableColumns().

◆ makeJsonTableSiblingJoin()

static JsonTablePlan * makeJsonTableSiblingJoin ( bool  cross,
JsonTablePlan lplan,
JsonTablePlan rplan 
)
static

Definition at line 715 of file parse_jsontable.c.

716{
718
719 join->plan.type = T_JsonTableSiblingJoin;
720 join->lplan = lplan;
721 join->rplan = rplan;
722 join->cross = cross;
723
724 return (JsonTablePlan *) join;
725}
JsonTablePlan * rplan
Definition primnodes.h:1950
JsonTablePlan * lplan
Definition primnodes.h:1949
JsonTablePlan plan
Definition primnodes.h:1947

References JsonTableSiblingJoin::cross, fb(), JsonTableSiblingJoin::lplan, makeNode, JsonTableSiblingJoin::plan, and JsonTableSiblingJoin::rplan.

Referenced by transformJsonTableNestedColumns().

◆ transformJsonTable()

ParseNamespaceItem * transformJsonTable ( ParseState pstate,
JsonTable jt 
)

Definition at line 84 of file parse_jsontable.c.

85{
86 TableFunc *tf;
88 JsonExpr *je;
91 bool is_lateral;
92 JsonTableParseContext cxt = {pstate};
93
94 Assert(IsA(rootPathSpec->string, A_Const) &&
95 castNode(A_Const, rootPathSpec->string)->val.node.type == T_String);
96
97 if (jt->on_error &&
103 errmsg("invalid %s behavior", "ON ERROR"),
104 errdetail("Only EMPTY [ ARRAY ] or ERROR is allowed in the top-level ON ERROR clause."),
105 parser_errposition(pstate, jt->on_error->location));
106
107 cxt.pathNameId = 0;
108
109 /*
110 * Collect the user-supplied path and column names, checking that they are
111 * distinct. If the row pattern path has an explicit name, it shares this
112 * namespace, so seed the list with it.
113 */
114 if (rootPathSpec->name != NULL)
115 cxt.pathNames = list_make1(rootPathSpec->name);
117
118 /*
119 * Generate a name for the row pattern path if it was not given one. Path
120 * names are optional for every path, including when a PLAN clause is
121 * present; a specific PLAN() can only reference named paths, so an
122 * unnamed path that the plan must mention is caught later as a path name
123 * mismatch or a path not covered by the plan. We generate the name only
124 * after collecting the user-supplied names above, so that it cannot
125 * collide with any of them.
126 */
127 if (rootPathSpec->name == NULL)
129
130 /*
131 * We make lateral_only names of this level visible, whether or not the
132 * RangeTableFunc is explicitly marked LATERAL. This is needed for SQL
133 * spec compliance and seems useful on convenience grounds for all
134 * functions in FROM.
135 *
136 * (LATERAL can't nest within a single pstate level, so we don't need
137 * save/restore logic here.)
138 */
139 Assert(!pstate->p_lateral_active);
140 pstate->p_lateral_active = true;
141
142 tf = makeNode(TableFunc);
144
145 /*
146 * Transform JsonFuncExpr representing the top JSON_TABLE context_item and
147 * pathspec into a dummy JSON_TABLE_OP JsonExpr.
148 */
150 jfe->op = JSON_TABLE_OP;
151 jfe->context_item = jt->context_item;
152 jfe->pathspec = (Node *) rootPathSpec->string;
153 jfe->passing = jt->passing;
154 jfe->on_empty = NULL;
155 jfe->on_error = jt->on_error;
156 jfe->location = jt->location;
158
159 /*
160 * Create a JsonTablePlan that will generate row pattern that becomes
161 * source data for JSON path expressions in jt->columns. This also adds
162 * the columns' transformed JsonExpr nodes into tf->colvalexprs.
163 */
164 cxt.jt = jt;
165 cxt.tf = tf;
166 tf->plan = (Node *) transformJsonTableColumns(&cxt, plan, jt->columns,
167 jt->passing,
169
170 /*
171 * Copy the transformed PASSING arguments into the TableFunc node, because
172 * they are evaluated separately from the JsonExpr that we just put in
173 * TableFunc.docexpr. JsonExpr.passing_values is still kept around for
174 * get_json_table().
175 */
176 je = (JsonExpr *) tf->docexpr;
177 tf->passingvalexprs = copyObject(je->passing_values);
178
179 tf->ordinalitycol = -1; /* undefine ordinality column number */
180 tf->location = jt->location;
181
182 pstate->p_lateral_active = false;
183
184 /*
185 * Mark the RTE as LATERAL if the user said LATERAL explicitly, or if
186 * there are any lateral cross-references in it.
187 */
188 is_lateral = jt->lateral || contain_vars_of_level((Node *) tf, 0);
189
190 return addRangeTableEntryForTableFunc(pstate,
191 tf, jt->alias, is_lateral, true);
192}
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define copyObject(obj)
Definition nodes.h:230
static char * generateJsonTablePathName(JsonTableParseContext *cxt)
static JsonTablePlan * transformJsonTableColumns(JsonTableParseContext *cxt, JsonTablePlanSpec *planspec, List *columns, List *passingArgs, JsonTablePathSpec *pathspec)
ParseNamespaceItem * addRangeTableEntryForTableFunc(ParseState *pstate, TableFunc *tf, Alias *alias, bool lateral, bool inFromCl)
#define list_make1(x1)
Definition pg_list.h:244
@ TFT_JSON_TABLE
Definition primnodes.h:102
@ JSON_BEHAVIOR_ERROR
Definition primnodes.h:1787
@ JSON_BEHAVIOR_EMPTY
Definition primnodes.h:1788
@ JSON_BEHAVIOR_EMPTY_ARRAY
Definition primnodes.h:1792
@ JSON_TABLE_OP
Definition primnodes.h:1826
ParseLoc location
Definition primnodes.h:1814
JsonBehaviorType btype
Definition primnodes.h:1811
JsonBehavior * on_error
List * columns
JsonTablePathSpec * pathspec
Alias * alias
List * passing
JsonTablePlanSpec * planspec
JsonValueExpr * context_item
ParseLoc location
bool p_lateral_active
Definition parse_node.h:224
ParseLoc location
Definition primnodes.h:147
TableFuncType functype
Definition primnodes.h:115
bool contain_vars_of_level(Node *node, int levelsup)
Definition var.c:444

References addRangeTableEntryForTableFunc(), JsonTable::alias, Assert, JsonBehavior::btype, castNode, CheckDuplicateColumnOrPathNames(), JsonTable::columns, contain_vars_of_level(), JsonTable::context_item, copyObject, TableFunc::docexpr, ereport, errcode(), errdetail(), errmsg, ERROR, EXPR_KIND_FROM_FUNCTION, fb(), TableFunc::functype, generateJsonTablePathName(), IsA, JSON_BEHAVIOR_EMPTY, JSON_BEHAVIOR_EMPTY_ARRAY, JSON_BEHAVIOR_ERROR, JSON_TABLE_OP, JsonTableParseContext::jt, JsonTable::lateral, list_make1, JsonTable::location, TableFunc::location, JsonBehavior::location, makeNode, JsonTable::on_error, ParseState::p_lateral_active, parser_errposition(), JsonTable::passing, JsonTableParseContext::pathNameId, JsonTableParseContext::pathNames, JsonTable::pathspec, plan, JsonTable::planspec, JsonTableParseContext::tf, TFT_JSON_TABLE, transformExpr(), and transformJsonTableColumns().

Referenced by transformFromClauseItem().

◆ transformJsonTableColumn()

static JsonFuncExpr * transformJsonTableColumn ( JsonTableColumn jtc,
Node contextItemExpr,
List passingArgs 
)
static

Definition at line 496 of file parse_jsontable.c.

498{
499 Node *pathspec;
501
502 if (jtc->coltype == JTC_REGULAR)
503 jfexpr->op = JSON_VALUE_OP;
504 else if (jtc->coltype == JTC_EXISTS)
506 else
507 jfexpr->op = JSON_QUERY_OP;
508
509 /* Pass the column name so any runtime JsonExpr errors can print it. */
510 Assert(jtc->name != NULL);
511 jfexpr->column_name = pstrdup(jtc->name);
512
513 jfexpr->context_item = makeJsonValueExpr((Expr *) contextItemExpr, NULL,
516 -1));
517 if (jtc->pathspec)
518 pathspec = (Node *) jtc->pathspec->string;
519 else
520 {
521 /* Construct default path as '$."column_name"' */
522 StringInfoData path;
523
524 initStringInfo(&path);
525
526 appendStringInfoString(&path, "$.");
527 escape_json(&path, jtc->name);
528
529 pathspec = makeStringConst(path.data, -1);
530 }
531 jfexpr->pathspec = pathspec;
532 jfexpr->passing = passingArgs;
533 jfexpr->output = makeNode(JsonOutput);
534 jfexpr->output->typeName = jtc->typeName;
535 jfexpr->output->returning = makeNode(JsonReturning);
536 jfexpr->output->returning->format = jtc->format;
537 jfexpr->on_empty = jtc->on_empty;
538 jfexpr->on_error = jtc->on_error;
539 jfexpr->quotes = jtc->quotes;
540 jfexpr->wrapper = jtc->wrapper;
541 jfexpr->location = jtc->location;
542
543 return jfexpr;
544}
void escape_json(StringInfo buf, const char *str)
Definition json.c:1572
Node * makeStringConst(char *str, int location)
Definition makefuncs.c:618
JsonValueExpr * makeJsonValueExpr(Expr *raw_expr, Expr *formatted_expr, JsonFormat *format)
Definition makefuncs.c:938
JsonFormat * makeJsonFormat(JsonFormatType type, JsonEncoding encoding, int location)
Definition makefuncs.c:922
@ JS_FORMAT_DEFAULT
Definition primnodes.h:1646
@ JS_ENC_DEFAULT
Definition primnodes.h:1634
@ JSON_QUERY_OP
Definition primnodes.h:1824
@ JSON_EXISTS_OP
Definition primnodes.h:1823
@ JSON_VALUE_OP
Definition primnodes.h:1825
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void initStringInfo(StringInfo str)
Definition stringinfo.c:97

References appendStringInfoString(), Assert, StringInfoData::data, escape_json(), fb(), initStringInfo(), JS_ENC_DEFAULT, JS_FORMAT_DEFAULT, JSON_EXISTS_OP, JSON_QUERY_OP, JSON_VALUE_OP, JTC_EXISTS, JTC_REGULAR, makeJsonFormat(), makeJsonValueExpr(), makeNode, makeStringConst(), and pstrdup().

Referenced by appendJsonTableColumns().

◆ transformJsonTableColumns()

static JsonTablePlan * transformJsonTableColumns ( JsonTableParseContext cxt,
JsonTablePlanSpec planspec,
List columns,
List passingArgs,
JsonTablePathSpec pathspec 
)
static

Definition at line 286 of file parse_jsontable.c.

291{
292 JsonTable *jt = cxt->jt;
293 TableFunc *tf = cxt->tf;
294 JsonTablePathScan *scan;
296 bool defaultPlan = planspec == NULL ||
297 planspec->plan_type == JSTP_DEFAULT;
298 bool errorOnError = jt->on_error &&
300 int colMin,
301 colMax;
303
304 /* Start of column range */
305 colMin = list_length(tf->colvalexprs);
306
307 if (defaultPlan)
308 childPlanSpec = planspec;
309 else
310 {
311 /* validate parent and child plans */
313
314 if (planspec->plan_type == JSTP_JOINED)
315 {
316 if (planspec->join_type != JSTP_JOIN_INNER &&
317 planspec->join_type != JSTP_JOIN_OUTER)
320 errmsg("invalid JSON_TABLE plan clause"),
321 errdetail("Expected INNER or OUTER."),
322 parser_errposition(cxt->pstate, planspec->location)));
323
324 parentPlanSpec = planspec->plan1;
325 childPlanSpec = planspec->plan2;
326
327 Assert(parentPlanSpec->plan_type != JSTP_JOINED);
328 Assert(parentPlanSpec->pathname);
329 }
330 else
331 {
332 parentPlanSpec = planspec;
334 }
335
336 if (strcmp(parentPlanSpec->pathname, pathspec->name) != 0)
339 errmsg("invalid JSON_TABLE plan"),
340 errdetail("PATH name mismatch: expected %s but %s is given.",
341 pathspec->name, parentPlanSpec->pathname),
342 parser_errposition(cxt->pstate, planspec->location)));
343
345 }
346
347 appendJsonTableColumns(cxt, columns, passingArgs);
348
349 /* End of column range. */
350 if (list_length(tf->colvalexprs) == colMin)
351 {
352 /* No columns in this Scan beside the nested ones. */
353 colMax = colMin = -1;
354 }
355 else
356 colMax = list_length(tf->colvalexprs) - 1;
357
359 {
360 /* transform recursively nested columns */
362 columns, passingArgs);
363 }
364
365 /* transform only non-nested columns */
366 scan = (JsonTablePathScan *) makeJsonTablePathScan(cxt, pathspec,
367 planspec,
368 errorOnError,
369 colMin,
370 colMax,
371 childplan);
372
373 return (JsonTablePlan *) scan;
374}
static JsonTablePlan * transformJsonTableNestedColumns(JsonTableParseContext *cxt, JsonTablePlanSpec *plan, List *passingArgs, List *columns)
static JsonTablePlan * makeJsonTablePathScan(JsonTableParseContext *cxt, JsonTablePathSpec *pathspec, JsonTablePlanSpec *planspec, bool errorOnError, int colMin, int colMax, JsonTablePlan *childplan)
static void appendJsonTableColumns(JsonTableParseContext *cxt, List *columns, List *passingArgs)
static void validateJsonTableChildPlan(JsonTableParseContext *cxt, JsonTablePlanSpec *plan, List *columns)
@ JSTP_DEFAULT
static int list_length(const List *l)
Definition pg_list.h:152
JsonTablePlanType plan_type
struct JsonTablePlanSpec * plan2
struct JsonTablePlanSpec * plan1

References appendJsonTableColumns(), Assert, JsonBehavior::btype, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), JsonTablePlanSpec::join_type, JSON_BEHAVIOR_ERROR, JSTP_DEFAULT, JSTP_JOIN_INNER, JSTP_JOIN_OUTER, JSTP_JOINED, JsonTableParseContext::jt, list_length(), JsonTablePlanSpec::location, makeJsonTablePathScan(), JsonTablePathSpec::name, JsonTable::on_error, parser_errposition(), JsonTablePlanSpec::plan1, JsonTablePlanSpec::plan2, JsonTablePlanSpec::plan_type, JsonTableParseContext::pstate, JsonTableParseContext::tf, transformJsonTableNestedColumns(), and validateJsonTableChildPlan().

Referenced by transformJsonTable(), and transformJsonTableNestedColumns().

◆ transformJsonTableNestedColumns()

static JsonTablePlan * transformJsonTableNestedColumns ( JsonTableParseContext cxt,
JsonTablePlanSpec plan,
List passingArgs,
List columns 
)
static

Definition at line 574 of file parse_jsontable.c.

578{
580
581 if (!planspec || planspec->plan_type == JSTP_DEFAULT)
582 {
583 /* unspecified or default plan */
585 ListCell *lc;
586 bool cross = planspec && (planspec->join_type & JSTP_JOIN_CROSS);
587
588 /*
589 * If there are multiple NESTED COLUMNS clauses in 'columns', their
590 * respective plans will be combined using a "sibling join" plan,
591 * which effectively does a UNION of the sets of rows coming from each
592 * nested plan.
593 */
594 foreach(lc, columns)
595 {
597 JsonTablePlan *nested;
598
599 if (col->coltype != JTC_NESTED)
600 continue;
601
602 if (col->pathspec->name == NULL)
603 {
604 col->pathspec->name = generateJsonTablePathName(cxt);
605 }
606
607 nested = transformJsonTableColumns(cxt, planspec, col->columns,
609 col->pathspec);
610
611 /* Join nested plan with previous sibling nested plans. */
612 if (plan)
613 plan = makeJsonTableSiblingJoin(cross, plan, nested);
614 else
615 plan = nested;
616 }
617
618 return plan;
619 }
620 else if (planspec->plan_type == JSTP_SIMPLE)
621 {
622 jtc = findNestedJsonTableColumn(columns, planspec->pathname);
623 }
624 else if (planspec->plan_type == JSTP_JOINED)
625 {
626 if (planspec->join_type == JSTP_JOIN_INNER ||
627 planspec->join_type == JSTP_JOIN_OUTER)
628 {
629 Assert(planspec->plan1->plan_type == JSTP_SIMPLE);
630 jtc = findNestedJsonTableColumn(columns, planspec->plan1->pathname);
631 }
632 else
633 {
635 planspec->plan1,
636 columns,
639 planspec->plan2,
640 columns,
642
643 return makeJsonTableSiblingJoin(planspec->join_type == JSTP_JOIN_CROSS,
644 lplan, rplan);
645 }
646 }
647 else
648 elog(ERROR, "invalid JSON_TABLE plan type %d", planspec->plan_type);
649
650 /*
651 * The plan's path names were already matched one-to-one against the
652 * nested columns by validateJsonTableChildPlan(), so a nested column with
653 * this path name must exist.
654 */
655 Assert(jtc != NULL);
656
657 return transformJsonTableColumns(cxt, planspec, jtc->columns,
659 jtc->pathspec);
660}
static JsonTablePlan * makeJsonTableSiblingJoin(bool cross, JsonTablePlan *lplan, JsonTablePlan *rplan)
static JsonTableColumn * findNestedJsonTableColumn(List *columns, const char *pathname)

References Assert, castNode, elog, ERROR, fb(), findNestedJsonTableColumn(), generateJsonTablePathName(), JsonTablePlanSpec::join_type, JSTP_DEFAULT, JSTP_JOIN_CROSS, JSTP_JOIN_INNER, JSTP_JOIN_OUTER, JSTP_JOINED, JSTP_SIMPLE, JTC_NESTED, lfirst, makeJsonTableSiblingJoin(), JsonTablePlanSpec::pathname, plan, JsonTablePlanSpec::plan1, JsonTablePlanSpec::plan2, JsonTablePlanSpec::plan_type, transformJsonTableColumns(), and transformJsonTableNestedColumns().

Referenced by transformJsonTableColumns(), and transformJsonTableNestedColumns().

◆ validateJsonTableChildPlan()

static void validateJsonTableChildPlan ( JsonTableParseContext cxt,
JsonTablePlanSpec plan,
List columns 
)
static

Definition at line 760 of file parse_jsontable.c.

762{
763 ParseState *pstate = cxt->pstate;
764 ListCell *lc1;
765 List *siblings = NIL;
766 int nchildren = 0;
767
768 if (plan)
770
771 foreach(lc1, columns)
772 {
774
775 if (jtc->coltype == JTC_NESTED)
776 {
777 ListCell *lc2;
778 bool found = false;
779
780 /*
781 * A NESTED path need not be named; generate a name if it was left
782 * unnamed. A generated name cannot be referenced by a specific
783 * PLAN(), so such a path is reported just below as a nested path
784 * not covered by the plan.
785 */
786 if (jtc->pathspec->name == NULL)
787 jtc->pathspec->name = generateJsonTablePathName(cxt);
788
789 /* find nested path name in the list of sibling path names */
790 foreach(lc2, siblings)
791 {
792 if ((found = !strcmp(jtc->pathspec->name, lfirst(lc2))))
793 break;
794 }
795
796 if (!found)
799 errmsg("invalid JSON_TABLE specification"),
800 errdetail("PLAN clause for nested path %s was not found.",
801 jtc->pathspec->name),
802 parser_errposition(pstate, jtc->location));
803
804 nchildren++;
805 }
806 }
807
811 errmsg("invalid JSON_TABLE plan clause"),
812 errdetail("PLAN clause contains some extra or duplicate sibling nodes."),
813 parser_errposition(pstate, plan ? plan->location : -1));
814}
#define NIL
Definition pg_list.h:68
Definition pg_list.h:54

References castNode, collectSiblingPathsInJsonTablePlan(), ereport, errcode(), errdetail(), errmsg, ERROR, fb(), generateJsonTablePathName(), JTC_NESTED, lfirst, list_length(), NIL, parser_errposition(), plan, and JsonTableParseContext::pstate.

Referenced by transformJsonTableColumns().