aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/execExpr.c17
-rw-r--r--src/backend/nodes/makefuncs.c7
-rw-r--r--src/backend/nodes/nodeFuncs.c4
-rw-r--r--src/backend/optimizer/util/clauses.c23
-rw-r--r--src/backend/parser/gram.y4
-rw-r--r--src/backend/parser/parse_expr.c57
-rw-r--r--src/include/nodes/makefuncs.h3
-rw-r--r--src/include/nodes/primnodes.h8
8 files changed, 56 insertions, 67 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index e6e616865c2..bf3a08c5f08 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 39e1884cf43..0e7e6e46d94 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -848,12 +848,13 @@ makeJsonFormat(JsonFormatType type, JsonEncoding encoding, int location)
* creates a JsonValueExpr node
*/
JsonValueExpr *
-makeJsonValueExpr(Expr *expr, JsonFormat *format)
+makeJsonValueExpr(Expr *raw_expr, Expr *formatted_expr,
+ JsonFormat *format)
{
JsonValueExpr *jve = makeNode(JsonValueExpr);
- jve->raw_expr = expr;
- jve->formatted_expr = NULL;
+ jve->raw_expr = raw_expr;
+ jve->formatted_expr = formatted_expr;
jve->format = format;
return jve;
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index c41e6bb984c..503d76aae07 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -225,9 +225,7 @@ exprType(const Node *expr)
{
const JsonValueExpr *jve = (const JsonValueExpr *) expr;
- type = exprType((Node *)
- (jve->formatted_expr ? jve->formatted_expr :
- jve->raw_expr));
+ type = exprType((Node *) jve->formatted_expr);
}
break;
case T_JsonConstructorExpr:
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 7f453b04f8b..da258968b8c 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/gram.y b/src/backend/parser/gram.y
index edb6c00ece6..c31b3733587 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -16353,7 +16353,9 @@ opt_asymmetric: ASYMMETRIC
json_value_expr:
a_expr json_format_clause_opt
{
- $$ = (Node *) makeJsonValueExpr((Expr *) $1, castNode(JsonFormat, $2));
+ /* formatted_expr will be set during parse-analysis. */
+ $$ = (Node *) makeJsonValueExpr((Expr *) $1, NULL,
+ castNode(JsonFormat, $2));
}
;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 286e85d7261..c08c06373a9 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -3203,23 +3203,12 @@ makeJsonByteaToTextConversion(Node *expr, JsonFormat *format, int location)
}
/*
- * Make a CaseTestExpr node.
- */
-static Node *
-makeCaseTestExpr(Node *expr)
-{
- CaseTestExpr *placeholder = makeNode(CaseTestExpr);
-
- placeholder->typeId = exprType(expr);
- placeholder->typeMod = exprTypmod(expr);
- placeholder->collation = exprCollation(expr);
-
- return (Node *) placeholder;
-}
-
-/*
* Transform JSON value expression using specified input JSON format or
* default format otherwise.
+ *
+ * Returned expression is either ve->raw_expr coerced to text (if needed) or
+ * a JsonValueExpr with formatted_expr set to the coerced copy of raw_expr
+ * if the specified format requires it.
*/
static Node *
transformJsonValueExpr(ParseState *pstate, const char *constructName,
@@ -3268,11 +3257,8 @@ transformJsonValueExpr(ParseState *pstate, const 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 +3296,7 @@ transformJsonValueExpr(ParseState *pstate, const char *constructName,
coerced = (Node *) fexpr;
}
- if (coerced == orig)
+ if (coerced == expr)
expr = rawexpr;
else
{
@@ -3322,6 +3308,10 @@ transformJsonValueExpr(ParseState *pstate, const char *constructName,
}
}
+ /* If returning a JsonValueExpr, formatted_expr must have been set. */
+ Assert(!IsA(expr, JsonValueExpr) ||
+ ((JsonValueExpr *) expr)->formatted_expr != NULL);
+
return expr;
}
@@ -3537,8 +3527,22 @@ makeJsonConstructorExpr(ParseState *pstate, JsonConstructorType type,
jsctor->absent_on_null = absent_on_null;
jsctor->location = location;
+ /*
+ * Coerce to the RETURNING type and format, if needed. We abuse
+ * CaseTestExpr here as placeholder to pass the result of either
+ * evaluating 'fexpr' or whatever is produced by ExecEvalJsonConstructor()
+ * that is of type JSON or JSONB to the coercion function.
+ */
if (fexpr)
- placeholder = makeCaseTestExpr((Node *) fexpr);
+ {
+ CaseTestExpr *cte = makeNode(CaseTestExpr);
+
+ cte->typeId = exprType((Node *) fexpr);
+ cte->typeMod = exprTypmod((Node *) fexpr);
+ cte->collation = exprCollation((Node *) fexpr);
+
+ placeholder = (Node *) cte;
+ }
else
{
CaseTestExpr *cte = makeNode(CaseTestExpr);
@@ -3635,7 +3639,12 @@ transformJsonArrayQueryConstructor(ParseState *pstate,
makeString(pstrdup("a")));
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 = makeJsonValueExpr((Expr *) colref, (Expr *) colref,
+ ctor->format);
agg->absent_on_null = ctor->absent_on_null;
agg->constructor = makeNode(JsonAggConstructor);
agg->constructor->agg_order = NIL;
@@ -3900,13 +3909,11 @@ transformJsonParseArg(ParseState *pstate, Node *jsexpr, JsonFormat *format,
{
JsonValueExpr *jve;
- expr = makeCaseTestExpr(raw_expr);
+ expr = raw_expr;
expr = makeJsonByteaToTextConversion(expr, format, exprLocation(expr));
*exprtype = TEXTOID;
- jve = makeJsonValueExpr((Expr *) raw_expr, format);
-
- jve->formatted_expr = (Expr *) expr;
+ jve = makeJsonValueExpr((Expr *) raw_expr, (Expr *) expr, format);
expr = (Node *) jve;
}
else
diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
index 06d991b7257..31807030055 100644
--- a/src/include/nodes/makefuncs.h
+++ b/src/include/nodes/makefuncs.h
@@ -110,7 +110,8 @@ extern VacuumRelation *makeVacuumRelation(RangeVar *relation, Oid oid, List *va_
extern JsonFormat *makeJsonFormat(JsonFormatType type, JsonEncoding encoding,
int location);
-extern JsonValueExpr *makeJsonValueExpr(Expr *expr, JsonFormat *format);
+extern JsonValueExpr *makeJsonValueExpr(Expr *raw_expr, Expr *formatted_expr,
+ JsonFormat *format);
extern Node *makeJsonKeyValue(Node *key, Node *value);
extern Node *makeJsonIsPredicate(Node *expr, JsonFormat *format,
JsonValueType item_type, bool unique_keys,
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 792a743f72e..e1aadc39cfb 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1264,6 +1264,8 @@ typedef struct CaseWhen
* see build_coercion_expression().
* * Nested FieldStore/SubscriptingRef assignment expressions in INSERT/UPDATE;
* see transformAssignmentIndirection().
+ * * Placeholder for intermediate results in some SQL/JSON expression nodes,
+ * such as JsonConstructorExpr.
*
* The uses in CaseExpr and ArrayCoerceExpr are safe only to the extent that
* there is not any other CaseExpr or ArrayCoerceExpr between the value source
@@ -1593,12 +1595,16 @@ typedef struct JsonReturning
/*
* JsonValueExpr -
* representation of JSON value expression (expr [FORMAT JsonFormat])
+ *
+ * The actual value is obtained by evaluating formatted_expr. raw_expr is
+ * only there for displaying the original user-written expression 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;