Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)