v4-0002-Don-t-include-CaseTestExpr-in-JsonValueExpr.forma.patch

application/octet-stream

Filename: v4-0002-Don-t-include-CaseTestExpr-in-JsonValueExpr.forma.patch
Type: application/octet-stream
Part: 5
Message: Re: remaining sql/json patches

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v4-0002
Subject: Don't include CaseTestExpr in JsonValueExpr.formatted_expr
File+
src/backend/executor/execExpr.c 2 15
src/backend/nodes/makefuncs.c 4 0
src/backend/optimizer/util/clauses.c 5 18
src/backend/parser/parse_expr.c 7 5
src/include/nodes/primnodes.h 4 1
From e2e69da761ba69557c8ed0f3908c370755d56292 Mon Sep 17 00:00:00 2001
From: Amit Langote <amitlan@postgresql.org>
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 <alvherre@alvh.no-ip.org>
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