Skip to content

Commit d8e9ebb

Browse files
author
Nikita Glukhov
committed
SQL/JSON functions
1 parent 9de426b commit d8e9ebb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+8332
-143
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

+41
Original file line numberDiff line numberDiff line change
@@ -2812,6 +2812,47 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
28122812
JumbleExpr(jstate, (Node *) conf->exclRelTlist);
28132813
}
28142814
break;
2815+
case T_JsonValueExpr:
2816+
{
2817+
JsonValueExpr *expr = (JsonValueExpr *) node;
2818+
2819+
JumbleExpr(jstate, (Node *) expr->expr);
2820+
APP_JUMB(expr->format.type);
2821+
APP_JUMB(expr->format.encoding);
2822+
}
2823+
break;
2824+
case T_JsonCtorOpts:
2825+
{
2826+
JsonCtorOpts *opts = (JsonCtorOpts *) node;
2827+
2828+
APP_JUMB(opts->returning.format.type);
2829+
APP_JUMB(opts->returning.format.encoding);
2830+
APP_JUMB(opts->returning.typid);
2831+
APP_JUMB(opts->returning.typmod);
2832+
APP_JUMB(opts->unique);
2833+
APP_JUMB(opts->absent_on_null);
2834+
}
2835+
break;
2836+
case T_JsonIsPredicateOpts:
2837+
{
2838+
JsonIsPredicateOpts *opts = (JsonIsPredicateOpts *) node;
2839+
2840+
APP_JUMB(opts->unique_keys);
2841+
APP_JUMB(opts->value_type);
2842+
}
2843+
break;
2844+
case T_JsonExpr:
2845+
{
2846+
JsonExpr *jexpr = (JsonExpr *) node;
2847+
2848+
APP_JUMB(jexpr->op);
2849+
JumbleExpr(jstate, jexpr->raw_expr);
2850+
JumbleExpr(jstate, jexpr->path_spec);
2851+
JumbleExpr(jstate, (Node *) jexpr->passing.values);
2852+
JumbleExpr(jstate, jexpr->on_empty.default_expr);
2853+
JumbleExpr(jstate, jexpr->on_error.default_expr);
2854+
}
2855+
break;
28152856
case T_List:
28162857
foreach(temp, (List *) node)
28172858
{

src/backend/executor/execExpr.c

+169-51
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "pgstat.h"
4646
#include "utils/builtins.h"
4747
#include "utils/datum.h"
48+
#include "utils/jsonpath.h"
4849
#include "utils/lsyscache.h"
4950
#include "utils/typcache.h"
5051

@@ -81,6 +82,40 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
8182
int transno, int setno, int setoff, bool ishash);
8283

8384

85+
static ExprState *
86+
ExecInitExprInternal(Expr *node, PlanState *parent, ParamListInfo ext_params,
87+
Datum *caseval, bool *casenull)
88+
{
89+
ExprState *state;
90+
ExprEvalStep scratch = {0};
91+
92+
/* Special case: NULL expression produces a NULL ExprState pointer */
93+
if (node == NULL)
94+
return NULL;
95+
96+
/* Initialize ExprState with empty step list */
97+
state = makeNode(ExprState);
98+
state->expr = node;
99+
state->parent = parent;
100+
state->ext_params = ext_params;
101+
state->innermost_caseval = caseval;
102+
state->innermost_casenull = casenull;
103+
104+
/* Insert EEOP_*_FETCHSOME steps as needed */
105+
ExecInitExprSlots(state, (Node *) node);
106+
107+
/* Compile the expression proper */
108+
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
109+
110+
/* Finally, append a DONE step */
111+
scratch.opcode = EEOP_DONE;
112+
ExprEvalPushStep(state, &scratch);
113+
114+
ExecReadyExpr(state);
115+
116+
return state;
117+
}
118+
84119
/*
85120
* ExecInitExpr: prepare an expression tree for execution
86121
*
@@ -119,32 +154,7 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
119154
ExprState *
120155
ExecInitExpr(Expr *node, PlanState *parent)
121156
{
122-
ExprState *state;
123-
ExprEvalStep scratch = {0};
124-
125-
/* Special case: NULL expression produces a NULL ExprState pointer */
126-
if (node == NULL)
127-
return NULL;
128-
129-
/* Initialize ExprState with empty step list */
130-
state = makeNode(ExprState);
131-
state->expr = node;
132-
state->parent = parent;
133-
state->ext_params = NULL;
134-
135-
/* Insert EEOP_*_FETCHSOME steps as needed */
136-
ExecInitExprSlots(state, (Node *) node);
137-
138-
/* Compile the expression proper */
139-
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
140-
141-
/* Finally, append a DONE step */
142-
scratch.opcode = EEOP_DONE;
143-
ExprEvalPushStep(state, &scratch);
144-
145-
ExecReadyExpr(state);
146-
147-
return state;
157+
return ExecInitExprInternal(node, parent, NULL, NULL, NULL);
148158
}
149159

150160
/*
@@ -156,32 +166,20 @@ ExecInitExpr(Expr *node, PlanState *parent)
156166
ExprState *
157167
ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
158168
{
159-
ExprState *state;
160-
ExprEvalStep scratch = {0};
161-
162-
/* Special case: NULL expression produces a NULL ExprState pointer */
163-
if (node == NULL)
164-
return NULL;
165-
166-
/* Initialize ExprState with empty step list */
167-
state = makeNode(ExprState);
168-
state->expr = node;
169-
state->parent = NULL;
170-
state->ext_params = ext_params;
171-
172-
/* Insert EEOP_*_FETCHSOME steps as needed */
173-
ExecInitExprSlots(state, (Node *) node);
174-
175-
/* Compile the expression proper */
176-
ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
177-
178-
/* Finally, append a DONE step */
179-
scratch.opcode = EEOP_DONE;
180-
ExprEvalPushStep(state, &scratch);
181-
182-
ExecReadyExpr(state);
169+
return ExecInitExprInternal(node, NULL, ext_params, NULL, NULL);
170+
}
183171

184-
return state;
172+
/*
173+
* ExecInitExprWithCaseValue: prepare an expression tree for execution
174+
*
175+
* This is the same as ExecInitExpr, except that a pointer to the value for
176+
* CasTestExpr is passed here.
177+
*/
178+
ExprState *
179+
ExecInitExprWithCaseValue(Expr *node, PlanState *parent,
180+
Datum *caseval, bool *casenull)
181+
{
182+
return ExecInitExprInternal(node, parent, NULL, caseval, casenull);
185183
}
186184

187185
/*
@@ -2115,6 +2113,126 @@ ExecInitExprRec(Expr *node, ExprState *state,
21152113
break;
21162114
}
21172115

2116+
case T_JsonValueExpr:
2117+
ExecInitExprRec(((JsonValueExpr *) node)->expr, state, resv,
2118+
resnull);
2119+
break;
2120+
2121+
case T_JsonExpr:
2122+
{
2123+
JsonExpr *jexpr = castNode(JsonExpr, node);
2124+
ListCell *argexprlc;
2125+
ListCell *argnamelc;
2126+
2127+
scratch.opcode = EEOP_JSONEXPR;
2128+
scratch.d.jsonexpr.jsexpr = jexpr;
2129+
2130+
scratch.d.jsonexpr.raw_expr =
2131+
palloc(sizeof(*scratch.d.jsonexpr.raw_expr));
2132+
2133+
ExecInitExprRec((Expr *) jexpr->raw_expr, state,
2134+
&scratch.d.jsonexpr.raw_expr->value,
2135+
&scratch.d.jsonexpr.raw_expr->isnull);
2136+
2137+
scratch.d.jsonexpr.pathspec =
2138+
palloc(sizeof(*scratch.d.jsonexpr.pathspec));
2139+
2140+
ExecInitExprRec((Expr *) jexpr->path_spec, state,
2141+
&scratch.d.jsonexpr.pathspec->value,
2142+
&scratch.d.jsonexpr.pathspec->isnull);
2143+
2144+
scratch.d.jsonexpr.formatted_expr =
2145+
ExecInitExprWithCaseValue((Expr *) jexpr->formatted_expr,
2146+
state->parent,
2147+
&scratch.d.jsonexpr.raw_expr->value,
2148+
&scratch.d.jsonexpr.raw_expr->isnull);
2149+
2150+
scratch.d.jsonexpr.res_expr =
2151+
palloc(sizeof(*scratch.d.jsonexpr.res_expr));
2152+
2153+
2154+
scratch.d.jsonexpr.result_expr = jexpr->result_coercion
2155+
? ExecInitExprWithCaseValue((Expr *) jexpr->result_coercion->expr,
2156+
state->parent,
2157+
&scratch.d.jsonexpr.res_expr->value,
2158+
&scratch.d.jsonexpr.res_expr->isnull)
2159+
: NULL;
2160+
2161+
scratch.d.jsonexpr.default_on_empty =
2162+
ExecInitExpr((Expr *) jexpr->on_empty.default_expr,
2163+
state->parent);
2164+
2165+
scratch.d.jsonexpr.default_on_error =
2166+
ExecInitExpr((Expr *) jexpr->on_error.default_expr,
2167+
state->parent);
2168+
2169+
if (jexpr->omit_quotes ||
2170+
(jexpr->result_coercion && jexpr->result_coercion->via_io))
2171+
{
2172+
Oid typinput;
2173+
2174+
/* lookup the result type's input function */
2175+
getTypeInputInfo(jexpr->returning.typid, &typinput,
2176+
&scratch.d.jsonexpr.input.typioparam);
2177+
fmgr_info(typinput, &scratch.d.jsonexpr.input.func);
2178+
}
2179+
2180+
scratch.d.jsonexpr.args = NIL;
2181+
2182+
forboth(argexprlc, jexpr->passing.values,
2183+
argnamelc, jexpr->passing.names)
2184+
{
2185+
Expr *argexpr = (Expr *) lfirst(argexprlc);
2186+
Value *argname = (Value *) lfirst(argnamelc);
2187+
JsonPathVariableEvalContext *var = palloc(sizeof(*var));
2188+
2189+
var->var.varName = cstring_to_text(argname->val.str);
2190+
var->var.typid = exprType((Node *) argexpr);
2191+
var->var.typmod = exprTypmod((Node *) argexpr);
2192+
var->var.cb = EvalJsonPathVar;
2193+
var->var.cb_arg = var;
2194+
var->estate = ExecInitExpr(argexpr, state->parent);
2195+
var->econtext = NULL;
2196+
var->evaluated = false;
2197+
var->value = (Datum) 0;
2198+
var->isnull = true;
2199+
2200+
scratch.d.jsonexpr.args =
2201+
lappend(scratch.d.jsonexpr.args, var);
2202+
}
2203+
2204+
scratch.d.jsonexpr.cache = NULL;
2205+
2206+
if (jexpr->coercions)
2207+
{
2208+
JsonCoercion **coercion;
2209+
struct JsonCoercionState *cstate;
2210+
Datum *caseval;
2211+
bool *casenull;
2212+
2213+
scratch.d.jsonexpr.coercion_expr =
2214+
palloc(sizeof(*scratch.d.jsonexpr.coercion_expr));
2215+
2216+
caseval = &scratch.d.jsonexpr.coercion_expr->value;
2217+
casenull = &scratch.d.jsonexpr.coercion_expr->isnull;
2218+
2219+
for (cstate = &scratch.d.jsonexpr.coercions.null,
2220+
coercion = &jexpr->coercions->null;
2221+
coercion <= &jexpr->coercions->composite;
2222+
coercion++, cstate++)
2223+
{
2224+
cstate->coercion = *coercion;
2225+
cstate->estate = *coercion ?
2226+
ExecInitExprWithCaseValue((Expr *)(*coercion)->expr,
2227+
state->parent,
2228+
caseval, casenull) : NULL;
2229+
}
2230+
}
2231+
2232+
ExprEvalPushStep(state, &scratch);
2233+
}
2234+
break;
2235+
21182236
default:
21192237
elog(ERROR, "unrecognized node type: %d",
21202238
(int) nodeTag(node));

0 commit comments

Comments
 (0)