From e2e69da761ba69557c8ed0f3908c370755d56292 Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Fri, 7 Jul 2023 20:21:58 +0900 Subject: [PATCH v4 2/7] Don't include CaseTestExpr in JsonValueExpr.formatted_expr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CaseTestExpr is normally (ab)used as a placeholder expression to represent the source value for computing an expression when the expression that provides the source value is computed independently. A CaseTestExpr is currently put into JsonValueExpr.formatted_expr as placeholder for the result of evaluating JsonValueExpr.raw_expr, which in turn is evaluated separately. Though, there's no need for this indirection if raw_expr itself can be embedded into formatted_expr and evaluated as part of evaluating the latter, so this commit makes it so. JsonValueExpr.raw_expr is no longer evaluated by ExecInterpExpr(), eval_const_exprs_mutator(), etc. and only used for displaying the original "unformatted" expression. Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/CA+HiwqE4XTdfb1nW=Ojoy_tQSRhYt-q_kb6i5d4xcKyrLC1Nbg@mail.gmail.com --- src/backend/executor/execExpr.c | 17 ++--------------- src/backend/nodes/makefuncs.c | 4 ++++ src/backend/optimizer/util/clauses.c | 23 +++++------------------ src/backend/parser/parse_expr.c | 12 +++++++----- src/include/nodes/primnodes.h | 5 ++++- 5 files changed, 22 insertions(+), 39 deletions(-) diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index e6e616865c..bf3a08c5f0 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -2294,21 +2294,8 @@ ExecInitExprRec(Expr *node, ExprState *state, { JsonValueExpr *jve = (JsonValueExpr *) node; - ExecInitExprRec(jve->raw_expr, state, resv, resnull); - - if (jve->formatted_expr) - { - Datum *innermost_caseval = state->innermost_caseval; - bool *innermost_isnull = state->innermost_casenull; - - state->innermost_caseval = resv; - state->innermost_casenull = resnull; - - ExecInitExprRec(jve->formatted_expr, state, resv, resnull); - - state->innermost_caseval = innermost_caseval; - state->innermost_casenull = innermost_isnull; - } + Assert(jve->formatted_expr != NULL); + ExecInitExprRec(jve->formatted_expr, state, resv, resnull); break; } diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 39e1884cf4..c6c310d253 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -853,6 +853,10 @@ makeJsonValueExpr(Expr *expr, JsonFormat *format) JsonValueExpr *jve = makeNode(JsonValueExpr); jve->raw_expr = expr; + + /* + * Set after checking the format, if needed, in transformJsonValueExpr(). + */ jve->formatted_expr = NULL; jve->format = format; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 7f453b04f8..da258968b8 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -2827,25 +2827,12 @@ eval_const_expressions_mutator(Node *node, case T_JsonValueExpr: { JsonValueExpr *jve = (JsonValueExpr *) node; - Node *raw; + Node *formatted; - raw = eval_const_expressions_mutator((Node *) jve->raw_expr, - context); - if (raw && IsA(raw, Const)) - { - Node *formatted; - Node *save_case_val = context->case_val; - - context->case_val = raw; - - formatted = eval_const_expressions_mutator((Node *) jve->formatted_expr, - context); - - context->case_val = save_case_val; - - if (formatted && IsA(formatted, Const)) - return formatted; - } + formatted = eval_const_expressions_mutator((Node *) jve->formatted_expr, + context); + if (formatted && IsA(formatted, Const)) + return formatted; break; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 5bf790cf0f..20cbb0a8e7 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -3268,11 +3268,8 @@ transformJsonValueExpr(ParseState *pstate, char *constructName, if (format != JS_FORMAT_DEFAULT) { Oid targettype = format == JS_FORMAT_JSONB ? JSONBOID : JSONOID; - Node *orig = makeCaseTestExpr(expr); Node *coerced; - expr = orig; - if (exprtype != BYTEAOID && typcategory != TYPCATEGORY_STRING) ereport(ERROR, errcode(ERRCODE_DATATYPE_MISMATCH), @@ -3310,7 +3307,7 @@ transformJsonValueExpr(ParseState *pstate, char *constructName, coerced = (Node *) fexpr; } - if (coerced == orig) + if (coerced == expr) expr = rawexpr; else { @@ -3636,6 +3633,11 @@ transformJsonArrayQueryConstructor(ParseState *pstate, colref->location = ctor->location; agg->arg = makeJsonValueExpr((Expr *) colref, ctor->format); + /* + * No formatting necessary, so set formatted_expr to be the same as + * raw_expr. + */ + agg->arg->formatted_expr = agg->arg->raw_expr; agg->absent_on_null = ctor->absent_on_null; agg->constructor = makeNode(JsonAggConstructor); agg->constructor->agg_order = NIL; @@ -3900,7 +3902,7 @@ transformJsonParseArg(ParseState *pstate, Node *jsexpr, JsonFormat *format, { JsonValueExpr *jve; - expr = makeCaseTestExpr(raw_expr); + expr = raw_expr; expr = makeJsonByteaToTextConversion(expr, format, exprLocation(expr)); *exprtype = TEXTOID; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 792a743f72..442d675600 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1593,12 +1593,15 @@ typedef struct JsonReturning /* * JsonValueExpr - * representation of JSON value expression (expr [FORMAT JsonFormat]) + * + * Note that raw_expr is only there for displaying and is not evaluated by + * ExecInterpExpr() and eval_const_exprs_mutator(). */ typedef struct JsonValueExpr { NodeTag type; Expr *raw_expr; /* raw expression */ - Expr *formatted_expr; /* formatted expression or NULL */ + Expr *formatted_expr; /* formatted expression */ JsonFormat *format; /* FORMAT clause, if specified */ } JsonValueExpr; -- 2.35.3