Skip to content

Commit 69ec8a0

Browse files
author
Nikita Glukhov
committed
Add JSON_TABLE
1 parent b23bb88 commit 69ec8a0

29 files changed

+3725
-105
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,9 +2887,11 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
28872887
{
28882888
TableFunc *tablefunc = (TableFunc *) node;
28892889

2890+
APP_JUMB(tablefunc->functype);
28902891
JumbleExpr(jstate, tablefunc->docexpr);
28912892
JumbleExpr(jstate, tablefunc->rowexpr);
28922893
JumbleExpr(jstate, (Node *) tablefunc->colexprs);
2894+
JumbleExpr(jstate, (Node *) tablefunc->colvalexprs);
28932895
}
28942896
break;
28952897
case T_TableSampleClause:

src/backend/commands/explain.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2752,7 +2752,9 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
27522752
break;
27532753
case T_TableFuncScan:
27542754
Assert(rte->rtekind == RTE_TABLEFUNC);
2755-
objectname = "xmltable";
2755+
objectname = rte->tablefunc ?
2756+
rte->tablefunc->functype == TFT_XMLTABLE ?
2757+
"xmltable" : "json_table" : NULL;
27562758
objecttag = "Table Function Name";
27572759
break;
27582760
case T_ValuesScan:

src/backend/executor/execExpr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2088,6 +2088,7 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
20882088
var->var.cb_arg = var;
20892089
var->estate = ExecInitExpr(argexpr, parent);
20902090
var->econtext = NULL;
2091+
var->mcxt = NULL;
20912092
var->evaluated = false;
20922093
var->value = (Datum) 0;
20932094
var->isnull = true;

src/backend/executor/execExprInterp.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3645,7 +3645,7 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
36453645
/*
36463646
* Evaluate a expression substituting specified value in its CaseTestExpr nodes.
36473647
*/
3648-
static Datum
3648+
Datum
36493649
ExecEvalExprPassingCaseValue(ExprState *estate, ExprContext *econtext,
36503650
bool *isnull,
36513651
Datum caseval_datum, bool caseval_isnull)
@@ -3705,6 +3705,7 @@ ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
37053705

37063706
case JSON_BEHAVIOR_NULL:
37073707
case JSON_BEHAVIOR_UNKNOWN:
3708+
case JSON_BEHAVIOR_EMPTY:
37083709
*is_null = true;
37093710
return (Datum) 0;
37103711

@@ -3765,8 +3766,14 @@ EvalJsonPathVar(void *cxt, bool *isnull)
37653766

37663767
if (!ecxt->evaluated)
37673768
{
3769+
MemoryContext oldcxt = ecxt->mcxt ?
3770+
MemoryContextSwitchTo(ecxt->mcxt) : NULL;
3771+
37683772
ecxt->value = ExecEvalExpr(ecxt->estate, ecxt->econtext, &ecxt->isnull);
37693773
ecxt->evaluated = true;
3774+
3775+
if (oldcxt)
3776+
MemoryContextSwitchTo(oldcxt);
37703777
}
37713778

37723779
*isnull = ecxt->isnull;
@@ -4033,6 +4040,11 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
40334040
*op->resnull = false;
40344041
break;
40354042

4043+
case IS_JSON_TABLE:
4044+
res = item;
4045+
*op->resnull = false;
4046+
break;
4047+
40364048
default:
40374049
elog(ERROR, "unrecognized SQL/JSON expression op %d",
40384050
jexpr->op);
@@ -4053,6 +4065,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
40534065
}
40544066

40554067
if (jexpr->op != IS_JSON_EXISTS &&
4068+
jexpr->op != IS_JSON_TABLE &&
40564069
(!empty ? jexpr->op != IS_JSON_VALUE :
40574070
/* result is already coerced in DEFAULT behavior case */
40584071
jexpr->on_empty.btype != JSON_BEHAVIOR_DEFAULT))

src/backend/executor/nodeTableFuncscan.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "executor/tablefunc.h"
2929
#include "miscadmin.h"
3030
#include "utils/builtins.h"
31+
#include "utils/jsonpath.h"
3132
#include "utils/lsyscache.h"
3233
#include "utils/memutils.h"
3334
#include "utils/xml.h"
@@ -167,8 +168,9 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
167168
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
168169
ExecAssignScanProjectionInfo(&scanstate->ss);
169170

170-
/* Only XMLTABLE is supported currently */
171-
scanstate->routine = &XmlTableRoutine;
171+
/* Only XMLTABLE and JSON_TABLE are supported currently */
172+
scanstate->routine =
173+
tf->functype == TFT_XMLTABLE ? &XmlTableRoutine : &JsonbTableRoutine;
172174

173175
scanstate->perValueCxt =
174176
AllocSetContextCreate(CurrentMemoryContext,
@@ -371,14 +373,17 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
371373
routine->SetNamespace(tstate, ns_name, ns_uri);
372374
}
373375

374-
/* Install the row filter expression into the table builder context */
375-
value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull);
376-
if (isnull)
377-
ereport(ERROR,
378-
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
379-
errmsg("row filter expression must not be null")));
376+
if (routine->SetRowFilter)
377+
{
378+
/* Install the row filter expression into the table builder context */
379+
value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull);
380+
if (isnull)
381+
ereport(ERROR,
382+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
383+
errmsg("row filter expression must not be null")));
380384

381-
routine->SetRowFilter(tstate, TextDatumGetCString(value));
385+
routine->SetRowFilter(tstate, TextDatumGetCString(value));
386+
}
382387

383388
/*
384389
* Install the column filter expressions into the table builder context.

src/backend/nodes/copyfuncs.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ _copyTableFunc(const TableFunc *from)
12241224
{
12251225
TableFunc *newnode = makeNode(TableFunc);
12261226

1227+
COPY_SCALAR_FIELD(functype);
12271228
COPY_NODE_FIELD(ns_uris);
12281229
COPY_NODE_FIELD(ns_names);
12291230
COPY_NODE_FIELD(docexpr);
@@ -1234,7 +1235,9 @@ _copyTableFunc(const TableFunc *from)
12341235
COPY_NODE_FIELD(colcollations);
12351236
COPY_NODE_FIELD(colexprs);
12361237
COPY_NODE_FIELD(coldefexprs);
1238+
COPY_NODE_FIELD(colvalexprs);
12371239
COPY_BITMAPSET_FIELD(notnulls);
1240+
COPY_NODE_FIELD(plan);
12381241
COPY_SCALAR_FIELD(ordinalitycol);
12391242
COPY_LOCATION_FIELD(location);
12401243

@@ -2364,6 +2367,99 @@ _copyJsonArgument(const JsonArgument *from)
23642367
return newnode;
23652368
}
23662369

2370+
/*
2371+
* _copyJsonTable
2372+
*/
2373+
static JsonTable *
2374+
_copyJsonTable(const JsonTable *from)
2375+
{
2376+
JsonTable *newnode = makeNode(JsonTable);
2377+
2378+
COPY_NODE_FIELD(common);
2379+
COPY_NODE_FIELD(columns);
2380+
COPY_NODE_FIELD(plan);
2381+
COPY_NODE_FIELD(on_error);
2382+
COPY_NODE_FIELD(alias);
2383+
COPY_SCALAR_FIELD(location);
2384+
2385+
return newnode;
2386+
}
2387+
2388+
/*
2389+
* _copyJsonTableColumn
2390+
*/
2391+
static JsonTableColumn *
2392+
_copyJsonTableColumn(const JsonTableColumn *from)
2393+
{
2394+
JsonTableColumn *newnode = makeNode(JsonTableColumn);
2395+
2396+
COPY_SCALAR_FIELD(coltype);
2397+
COPY_STRING_FIELD(name);
2398+
COPY_NODE_FIELD(typename);
2399+
COPY_STRING_FIELD(pathspec);
2400+
COPY_STRING_FIELD(pathname);
2401+
COPY_SCALAR_FIELD(format);
2402+
COPY_SCALAR_FIELD(wrapper);
2403+
COPY_SCALAR_FIELD(omit_quotes);
2404+
COPY_NODE_FIELD(columns);
2405+
COPY_NODE_FIELD(on_empty);
2406+
COPY_NODE_FIELD(on_error);
2407+
COPY_SCALAR_FIELD(location);
2408+
2409+
return newnode;
2410+
}
2411+
2412+
/*
2413+
* _copyJsonTablePlan
2414+
*/
2415+
static JsonTablePlan *
2416+
_copyJsonTablePlan(const JsonTablePlan *from)
2417+
{
2418+
JsonTablePlan *newnode = makeNode(JsonTablePlan);
2419+
2420+
COPY_SCALAR_FIELD(plan_type);
2421+
COPY_SCALAR_FIELD(join_type);
2422+
COPY_STRING_FIELD(pathname);
2423+
COPY_NODE_FIELD(plan1);
2424+
COPY_NODE_FIELD(plan2);
2425+
COPY_SCALAR_FIELD(location);
2426+
2427+
return newnode;
2428+
}
2429+
2430+
/*
2431+
* _copyJsonTableParentNode
2432+
*/
2433+
static JsonTableParentNode *
2434+
_copyJsonTableParentNode(const JsonTableParentNode *from)
2435+
{
2436+
JsonTableParentNode *newnode = makeNode(JsonTableParentNode);
2437+
2438+
COPY_NODE_FIELD(path);
2439+
COPY_STRING_FIELD(name);
2440+
COPY_NODE_FIELD(child);
2441+
COPY_SCALAR_FIELD(outerJoin);
2442+
COPY_SCALAR_FIELD(colMin);
2443+
COPY_SCALAR_FIELD(colMax);
2444+
2445+
return newnode;
2446+
}
2447+
2448+
/*
2449+
* _copyJsonTableSiblingNode
2450+
*/
2451+
static JsonTableSiblingNode *
2452+
_copyJsonTableSiblingNode(const JsonTableSiblingNode *from)
2453+
{
2454+
JsonTableSiblingNode *newnode = makeNode(JsonTableSiblingNode);
2455+
2456+
COPY_NODE_FIELD(larg);
2457+
COPY_NODE_FIELD(rarg);
2458+
COPY_SCALAR_FIELD(cross);
2459+
2460+
return newnode;
2461+
}
2462+
23672463
/* ****************************************************************
23682464
* relation.h copy functions
23692465
*
@@ -5273,6 +5369,21 @@ copyObjectImpl(const void *from)
52735369
case T_JsonArgument:
52745370
retval = _copyJsonArgument(from);
52755371
break;
5372+
case T_JsonTable:
5373+
retval = _copyJsonTable(from);
5374+
break;
5375+
case T_JsonTableColumn:
5376+
retval = _copyJsonTableColumn(from);
5377+
break;
5378+
case T_JsonTablePlan:
5379+
retval = _copyJsonTablePlan(from);
5380+
break;
5381+
case T_JsonTableParentNode:
5382+
retval = _copyJsonTableParentNode(from);
5383+
break;
5384+
case T_JsonTableSiblingNode:
5385+
retval = _copyJsonTableSiblingNode(from);
5386+
break;
52765387

52775388
/*
52785389
* RELATION NODES

src/backend/nodes/equalfuncs.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ _equalRangeVar(const RangeVar *a, const RangeVar *b)
119119
static bool
120120
_equalTableFunc(const TableFunc *a, const TableFunc *b)
121121
{
122+
COMPARE_SCALAR_FIELD(functype);
122123
COMPARE_NODE_FIELD(ns_uris);
123124
COMPARE_NODE_FIELD(ns_names);
124125
COMPARE_NODE_FIELD(docexpr);
@@ -129,13 +130,38 @@ _equalTableFunc(const TableFunc *a, const TableFunc *b)
129130
COMPARE_NODE_FIELD(colcollations);
130131
COMPARE_NODE_FIELD(colexprs);
131132
COMPARE_NODE_FIELD(coldefexprs);
133+
COMPARE_NODE_FIELD(colvalexprs);
132134
COMPARE_BITMAPSET_FIELD(notnulls);
135+
COMPARE_NODE_FIELD(plan);
133136
COMPARE_SCALAR_FIELD(ordinalitycol);
134137
COMPARE_LOCATION_FIELD(location);
135138

136139
return true;
137140
}
138141

142+
static bool
143+
_equalJsonTableParentNode(const JsonTableParentNode *a, const JsonTableParentNode *b)
144+
{
145+
COMPARE_NODE_FIELD(path);
146+
COMPARE_STRING_FIELD(name);
147+
COMPARE_NODE_FIELD(child);
148+
COMPARE_SCALAR_FIELD(outerJoin);
149+
COMPARE_SCALAR_FIELD(colMin);
150+
COMPARE_SCALAR_FIELD(colMax);
151+
152+
return true;
153+
}
154+
155+
static bool
156+
_equalJsonTableSiblingNode(const JsonTableSiblingNode *a, const JsonTableSiblingNode *b)
157+
{
158+
COMPARE_NODE_FIELD(larg);
159+
COMPARE_NODE_FIELD(rarg);
160+
COMPARE_SCALAR_FIELD(cross);
161+
162+
return true;
163+
}
164+
139165
static bool
140166
_equalIntoClause(const IntoClause *a, const IntoClause *b)
141167
{
@@ -3183,6 +3209,12 @@ equal(const void *a, const void *b)
31833209
case T_JsonExpr:
31843210
retval = _equalJsonExpr(a, b);
31853211
break;
3212+
case T_JsonTableParentNode:
3213+
retval = _equalJsonTableParentNode(a, b);
3214+
break;
3215+
case T_JsonTableSiblingNode:
3216+
retval = _equalJsonTableSiblingNode(a, b);
3217+
break;
31863218

31873219
/*
31883220
* RELATION NODES

src/backend/nodes/makefuncs.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,25 @@ makeJsonBehavior(JsonBehaviorType type, Node *default_expr)
645645
return behavior;
646646
}
647647

648+
/*
649+
* makeJsonTableJoinedPlan -
650+
* creates a joined JsonTablePlan node
651+
*/
652+
Node *
653+
makeJsonTableJoinedPlan(JsonTablePlanJoinType type, Node *plan1, Node *plan2,
654+
int location)
655+
{
656+
JsonTablePlan *n = makeNode(JsonTablePlan);
657+
658+
n->plan_type = JSTP_JOINED;
659+
n->join_type = type;
660+
n->plan1 = castNode(JsonTablePlan, plan1);
661+
n->plan2 = castNode(JsonTablePlan, plan2);
662+
n->location = location;
663+
664+
return (Node *) n;
665+
}
666+
648667
/*
649668
* makeJsonEncoding -
650669
* converts JSON encoding name to enum JsonEncoding

0 commit comments

Comments
 (0)