Skip to content

Commit 39d0a43

Browse files
author
Nikita Glukhov
committed
Refactor output coercion in SQL/JSON constructors
1 parent 7548800 commit 39d0a43

File tree

9 files changed

+122
-61
lines changed

9 files changed

+122
-61
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3117,6 +3117,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
31173117
JsonCtorExpr *ctor = (JsonCtorExpr *) node;
31183118

31193119
JumbleExpr(jstate, (Node *) ctor->func);
3120+
JumbleExpr(jstate, (Node *) ctor->coercion);
31203121
JumbleExpr(jstate, (Node *) ctor->returning);
31213122
APP_JUMB(ctor->type);
31223123
APP_JUMB(ctor->unique);

src/backend/executor/execExpr.c

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,40 +2141,55 @@ ExecInitExprRec(Expr *node, ExprState *state,
21412141
if (ctor->func)
21422142
{
21432143
ExecInitExprRec(ctor->func, state, resv, resnull);
2144-
break;
21452144
}
2146-
2147-
scratch.opcode = EEOP_JSON_CTOR;
2148-
scratch.d.json_ctor.ctor = ctor;
2149-
scratch.d.json_ctor.arg_values = palloc(sizeof(Datum) * nargs);
2150-
scratch.d.json_ctor.arg_nulls = palloc(sizeof(bool) * nargs);
2151-
scratch.d.json_ctor.arg_types = palloc(sizeof(Oid) * nargs);
2152-
scratch.d.json_ctor.nargs = nargs;
2153-
2154-
foreach(lc, args)
2145+
else
21552146
{
2156-
Expr *arg = (Expr *) lfirst(lc);
2147+
scratch.opcode = EEOP_JSON_CTOR;
2148+
scratch.d.json_ctor.ctor = ctor;
2149+
scratch.d.json_ctor.arg_values = palloc(sizeof(Datum) * nargs);
2150+
scratch.d.json_ctor.arg_nulls = palloc(sizeof(bool) * nargs);
2151+
scratch.d.json_ctor.arg_types = palloc(sizeof(Oid) * nargs);
2152+
scratch.d.json_ctor.nargs = nargs;
2153+
2154+
foreach(lc, args)
2155+
{
2156+
Expr *arg = (Expr *) lfirst(lc);
21572157

2158-
scratch.d.json_ctor.arg_types[argno] = exprType((Node *) arg);
2158+
scratch.d.json_ctor.arg_types[argno] = exprType((Node *) arg);
21592159

2160-
if (IsA(arg, Const))
2161-
{
2162-
/* Don't evaluate const arguments every round */
2163-
Const *con = (Const *) arg;
2160+
if (IsA(arg, Const))
2161+
{
2162+
/* Don't evaluate const arguments every round */
2163+
Const *con = (Const *) arg;
21642164

2165-
scratch.d.json_ctor.arg_values[argno] = con->constvalue;
2166-
scratch.d.json_ctor.arg_nulls[argno] = con->constisnull;
2167-
}
2168-
else
2169-
{
2170-
ExecInitExprRec(arg, state,
2171-
&scratch.d.json_ctor.arg_values[argno],
2172-
&scratch.d.json_ctor.arg_nulls[argno]);
2165+
scratch.d.json_ctor.arg_values[argno] = con->constvalue;
2166+
scratch.d.json_ctor.arg_nulls[argno] = con->constisnull;
2167+
}
2168+
else
2169+
{
2170+
ExecInitExprRec(arg, state,
2171+
&scratch.d.json_ctor.arg_values[argno],
2172+
&scratch.d.json_ctor.arg_nulls[argno]);
2173+
}
2174+
argno++;
21732175
}
2174-
argno++;
2176+
2177+
ExprEvalPushStep(state, &scratch);
21752178
}
21762179

2177-
ExprEvalPushStep(state, &scratch);
2180+
if (ctor->coercion)
2181+
{
2182+
Datum *innermost_caseval = state->innermost_caseval;
2183+
bool *innermost_isnull = state->innermost_casenull;
2184+
2185+
state->innermost_caseval = resv;
2186+
state->innermost_casenull = resnull;
2187+
2188+
ExecInitExprRec(ctor->coercion, state, resv, resnull);
2189+
2190+
state->innermost_caseval = innermost_caseval;
2191+
state->innermost_casenull = innermost_isnull;
2192+
}
21782193
}
21792194
break;
21802195

src/backend/nodes/copyfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2302,9 +2302,10 @@ _copyJsonCtorExpr(const JsonCtorExpr *from)
23022302
{
23032303
JsonCtorExpr *newnode = makeNode(JsonCtorExpr);
23042304

2305+
COPY_SCALAR_FIELD(type);
23052306
COPY_NODE_FIELD(args);
23062307
COPY_NODE_FIELD(func);
2307-
COPY_SCALAR_FIELD(type);
2308+
COPY_NODE_FIELD(coercion);
23082309
COPY_NODE_FIELD(returning);
23092310
COPY_SCALAR_FIELD(absent_on_null);
23102311
COPY_SCALAR_FIELD(unique);

src/backend/nodes/equalfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,9 +851,10 @@ _equalJsonValueExpr(const JsonValueExpr *a, const JsonValueExpr *b)
851851
static bool
852852
_equalJsonCtorExpr(const JsonCtorExpr *a, const JsonCtorExpr *b)
853853
{
854+
COMPARE_SCALAR_FIELD(type);
854855
COMPARE_NODE_FIELD(args);
855856
COMPARE_NODE_FIELD(func);
856-
COMPARE_SCALAR_FIELD(type);
857+
COMPARE_NODE_FIELD(coercion);
857858
COMPARE_NODE_FIELD(returning);
858859
COMPARE_SCALAR_FIELD(absent_on_null);
859860
COMPARE_SCALAR_FIELD(unique);

src/backend/nodes/nodeFuncs.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ exprType(const Node *expr)
266266
}
267267
break;
268268
case T_JsonCtorExpr:
269-
type = ((const JsonCtorExpr *) expr)->returning->format->format == JS_FORMAT_JSONB ? JSONBOID : JSONOID;
269+
type = ((const JsonCtorExpr *) expr)->returning->typid;
270270
break;
271271
default:
272272
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -924,8 +924,14 @@ exprCollation(const Node *expr)
924924
coll = exprCollation((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
925925
break;
926926
case T_JsonCtorExpr:
927-
/* coll = exprCollation((Node *) ((const JsonCtorExpr *) expr)->func); */
928-
coll = InvalidOid; /* keep compiler quiet */
927+
{
928+
const JsonCtorExpr *ctor = (const JsonCtorExpr *) expr;
929+
930+
if (ctor->coercion)
931+
coll = exprCollation((Node *) ctor->coercion);
932+
else
933+
coll = InvalidOid;
934+
}
929935
break;
930936
default:
931937
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -1135,8 +1141,14 @@ exprSetCollation(Node *expr, Oid collation)
11351141
collation);
11361142
break;
11371143
case T_JsonCtorExpr:
1138-
/* exprSetCollation((Node *) ((const JsonCtorExpr *) expr)->func, collation); */
1139-
Assert(!OidIsValid(collation)); /* result is always an json[b] type */
1144+
{
1145+
JsonCtorExpr *ctor = (JsonCtorExpr *) expr;
1146+
1147+
if (ctor->coercion)
1148+
exprSetCollation((Node *) ctor->coercion, collation);
1149+
else
1150+
Assert(!OidIsValid(collation)); /* result is always an json[b] type */
1151+
}
11401152
break;
11411153
default:
11421154
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -2299,6 +2311,8 @@ expression_tree_walker(Node *node,
22992311
return true;
23002312
if (walker(ctor->func, context))
23012313
return true;
2314+
if (walker(ctor->coercion, context))
2315+
return true;
23022316
}
23032317
break;
23042318
default:
@@ -3255,6 +3269,7 @@ expression_tree_mutator(Node *node,
32553269
FLATCOPY(newnode, jve, JsonCtorExpr);
32563270
MUTATE(newnode->args, jve->args, List *);
32573271
MUTATE(newnode->func, jve->func, Expr *);
3272+
MUTATE(newnode->coercion, jve->coercion, Expr *);
32583273
MUTATE(newnode->returning, jve->returning, JsonReturning *);
32593274

32603275
return (Node *) newnode;
@@ -3976,6 +3991,8 @@ raw_expression_tree_walker(Node *node,
39763991
return true;
39773992
if (walker(ctor->func, context))
39783993
return true;
3994+
if (walker(ctor->coercion, context))
3995+
return true;
39793996
if (walker(ctor->returning, context))
39803997
return true;
39813998
}

src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,7 @@ _outJsonCtorExpr(StringInfo str, const JsonCtorExpr *node)
17461746

17471747
WRITE_NODE_FIELD(args);
17481748
WRITE_NODE_FIELD(func);
1749+
WRITE_NODE_FIELD(coercion);
17491750
WRITE_INT_FIELD(type);
17501751
WRITE_NODE_FIELD(returning);
17511752
WRITE_BOOL_FIELD(unique);

src/backend/nodes/readfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,7 @@ _readJsonCtorExpr(void)
13981398

13991399
READ_NODE_FIELD(args);
14001400
READ_NODE_FIELD(func);
1401+
READ_NODE_FIELD(coercion);
14011402
READ_INT_FIELD(type);
14021403
READ_NODE_FIELD(returning);
14031404
READ_BOOL_FIELD(unique);

src/backend/parser/parse_expr.c

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3974,6 +3974,46 @@ coerceJsonFuncExpr(ParseState *pstate, Node *expr,
39743974
return res;
39753975
}
39763976

3977+
static Node *
3978+
makeJsonCtorExpr(ParseState *pstate, JsonCtorType type, List *args, Expr *fexpr,
3979+
JsonReturning *returning, bool unique, bool absent_on_null,
3980+
int location)
3981+
{
3982+
Node *placeholder;
3983+
Node *coercion;
3984+
JsonCtorExpr *jsctor = makeNode(JsonCtorExpr);
3985+
Oid intermediate_typid =
3986+
returning->format->format == JS_FORMAT_JSONB ? JSONBOID : JSONOID;
3987+
3988+
jsctor->args = args;
3989+
jsctor->func = fexpr;
3990+
jsctor->type = type;
3991+
jsctor->returning = returning;
3992+
jsctor->unique = unique;
3993+
jsctor->absent_on_null = absent_on_null;
3994+
jsctor->location = location;
3995+
3996+
if (fexpr)
3997+
placeholder = makeCaseTestExpr((Node *) fexpr);
3998+
else
3999+
{
4000+
CaseTestExpr *cte = makeNode(CaseTestExpr);
4001+
4002+
cte->typeId = intermediate_typid;
4003+
cte->typeMod = -1;
4004+
cte->collation = InvalidOid;
4005+
4006+
placeholder = (Node *) cte;
4007+
}
4008+
4009+
coercion = coerceJsonFuncExpr(pstate, placeholder, returning, true);
4010+
4011+
if (coercion != placeholder)
4012+
jsctor->coercion = (Expr *) coercion;
4013+
4014+
return (Node *) jsctor;
4015+
}
4016+
39774017
/*
39784018
* Transform JSON_OBJECT() constructor.
39794019
*
@@ -3986,7 +4026,7 @@ coerceJsonFuncExpr(ParseState *pstate, Node *expr,
39864026
static Node *
39874027
transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
39884028
{
3989-
JsonCtorExpr *jsctor;
4029+
JsonReturning *returning;
39904030
List *args = NIL;
39914031

39924032
/* transform key-value pairs, if any */
@@ -4007,15 +4047,11 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
40074047
}
40084048
}
40094049

4010-
jsctor = makeNode(JsonCtorExpr);
4011-
jsctor->args = args;
4012-
jsctor->type = JSCTOR_JSON_OBJECT;
4013-
jsctor->returning = transformJsonCtorOutput(pstate, ctor->output, args);
4014-
jsctor->unique = ctor->unique;
4015-
jsctor->absent_on_null = ctor->absent_on_null;
4016-
jsctor->location = ctor->location;
4050+
returning = transformJsonCtorOutput(pstate, ctor->output, args);
40174051

4018-
return coerceJsonFuncExpr(pstate, (Node *) jsctor, jsctor->returning, true);
4052+
return makeJsonCtorExpr(pstate, JSCTOR_JSON_OBJECT, args, NULL,
4053+
returning, ctor->unique, ctor->absent_on_null,
4054+
ctor->location);
40194055
}
40204056

40214057
/*
@@ -4093,7 +4129,6 @@ transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor,
40934129
bool unique, bool absent_on_null)
40944130
{
40954131
Oid aggfnoid;
4096-
JsonCtorExpr *jsctor;
40974132
Node *node;
40984133
Expr *aggfilter = agg_ctor->agg_filter ? (Expr *)
40994134
transformWhereClause(pstate, agg_ctor->agg_filter,
@@ -4156,15 +4191,8 @@ transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor,
41564191
node = (Node *) aggref;
41574192
}
41584193

4159-
jsctor = makeNode(JsonCtorExpr);
4160-
jsctor->func = (Expr *) node;
4161-
jsctor->type = ctor_type;
4162-
jsctor->returning = returning;
4163-
jsctor->unique = unique;
4164-
jsctor->absent_on_null = absent_on_null;
4165-
jsctor->location = agg_ctor->location;
4166-
4167-
return coerceJsonFuncExpr(pstate, (Node *) jsctor, returning, true);
4194+
return makeJsonCtorExpr(pstate, ctor_type, NIL, (Expr *) node, returning,
4195+
unique, absent_on_null, agg_ctor->location);
41684196
}
41694197

41704198
/*
@@ -4277,7 +4305,7 @@ transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg)
42774305
static Node *
42784306
transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor)
42794307
{
4280-
JsonCtorExpr *jsctor;
4308+
JsonReturning *returning;
42814309
List *args = NIL;
42824310

42834311
/* transform element expressions, if any */
@@ -4296,13 +4324,8 @@ transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor)
42964324
}
42974325
}
42984326

4299-
jsctor = makeNode(JsonCtorExpr);
4300-
jsctor->args = args;
4301-
jsctor->type = JSCTOR_JSON_ARRAY;
4302-
jsctor->returning = transformJsonCtorOutput(pstate, ctor->output, args);
4303-
jsctor->unique = false;
4304-
jsctor->absent_on_null = ctor->absent_on_null;
4305-
jsctor->location = ctor->location;
4327+
returning = transformJsonCtorOutput(pstate, ctor->output, args);
43064328

4307-
return coerceJsonFuncExpr(pstate, (Node *) jsctor, jsctor->returning, true);
4329+
return makeJsonCtorExpr(pstate, JSCTOR_JSON_ARRAY, args, NULL, returning,
4330+
false, ctor->absent_on_null, ctor->location);
43084331
}

src/include/nodes/primnodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,7 @@ typedef struct JsonCtorExpr
12661266
JsonCtorType type; /* constructor type */
12671267
List *args;
12681268
Expr *func; /* underlying json[b]_xxx() function call */
1269+
Expr *coercion; /* coercion to RETURNING type */
12691270
JsonReturning *returning; /* RETURNING clause */
12701271
bool absent_on_null; /* ABSENT ON NULL? */
12711272
bool unique; /* WITH UNIQUE KEYS? (JSON_OBJECT[AGG] only) */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy