Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfa4f118

Browse files
committed
SQL/JSON: Fix some oversights in commitb6e1157
The decision inb6e1157 to ignore raw_expr when evaluating aJsonValueExpr was incorrect. While its value is not ultimatelyused (since formatted_expr's value is), failing to initialize itcan lead to problems, for instance, when the expression tree inraw_expr contains Aggref nodes, which must be initialized toensure the parent Agg node works correctly.Also, optimize eval_const_expressions_mutator()'s handling ofJsonValueExpr a bit. Currently, when formatted_expr cannot be foldedinto a constant, we end up processing it twice -- once directly ineval_const_expressions_mutator() and again recursively viaece_generic_processing(). This recursive processing is required tohandle raw_expr. To avoid the redundant processing of formatted_expr,we now process raw_expr directly in eval_const_expressions_mutator().Finally, update the comment of JsonValueExpr to describe the roles ofraw_expr and formatted_expr more clearly.Bug: #18657Reported-by: Alexander Lakhin <exclusion@gmail.com>Diagnosed-by: Fabio R. Sluzala <fabio3rs@gmail.com>Diagnosed-by: Tender Wang <tndrwang@gmail.com>Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>Discussion:https://postgr.es/m/18657-1b90ccce2b16bdb8@postgresql.orgBackpatch-through: 16
1 parent0f40458 commitfa4f118

File tree

5 files changed

+92
-11
lines changed

5 files changed

+92
-11
lines changed

‎src/backend/executor/execExpr.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,8 @@ ExecInitExprRec(Expr *node, ExprState *state,
22942294
{
22952295
JsonValueExpr*jve= (JsonValueExpr*)node;
22962296

2297+
Assert(jve->raw_expr!=NULL);
2298+
ExecInitExprRec(jve->raw_expr,state,resv,resnull);
22972299
Assert(jve->formatted_expr!=NULL);
22982300
ExecInitExprRec(jve->formatted_expr,state,resv,resnull);
22992301
break;

‎src/backend/optimizer/util/clauses.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2897,13 +2897,25 @@ eval_const_expressions_mutator(Node *node,
28972897
caseT_JsonValueExpr:
28982898
{
28992899
JsonValueExpr*jve= (JsonValueExpr*)node;
2900-
Node*formatted;
2900+
Node*raw_expr= (Node*)jve->raw_expr;
2901+
Node*formatted_expr= (Node*)jve->formatted_expr;
29012902

2902-
formatted=eval_const_expressions_mutator((Node*)jve->formatted_expr,
2903-
context);
2904-
if (formatted&&IsA(formatted,Const))
2905-
returnformatted;
2906-
break;
2903+
/*
2904+
* If we can fold formatted_expr to a constant, we can elide
2905+
* the JsonValueExpr altogether. Otherwise we must process
2906+
* raw_expr too. But JsonFormat is a flat node and requires
2907+
* no simplification, only copying.
2908+
*/
2909+
formatted_expr=eval_const_expressions_mutator(formatted_expr,
2910+
context);
2911+
if (formatted_expr&&IsA(formatted_expr,Const))
2912+
returnformatted_expr;
2913+
2914+
raw_expr=eval_const_expressions_mutator(raw_expr,context);
2915+
2916+
return (Node*)makeJsonValueExpr((Expr*)raw_expr,
2917+
(Expr*)formatted_expr,
2918+
copyObject(jve->format));
29072919
}
29082920

29092921
caseT_SubPlan:

‎src/include/nodes/primnodes.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,15 +1596,19 @@ typedef struct JsonReturning
15961596
* JsonValueExpr -
15971597
*representation of JSON value expression (expr [FORMAT JsonFormat])
15981598
*
1599-
* The actual value is obtained by evaluating formatted_expr. raw_expr is
1600-
* only there for displaying the original user-written expression and is not
1601-
* evaluated by ExecInterpExpr() and eval_const_exprs_mutator().
1599+
* raw_expr is the user-specified value, while formatted_expr is the value
1600+
* obtained by coercing raw_expr to the type required by either the FORMAT
1601+
* clause or an enclosing node's RETURNING clause.
1602+
*
1603+
* When deparsing a JsonValueExpr, get_rule_expr() prints raw_expr. However,
1604+
* during the evaluation of a JsonValueExpr, the value of formatted_expr
1605+
* takes precedence over that of raw_expr.
16021606
*/
16031607
typedefstructJsonValueExpr
16041608
{
16051609
NodeTagtype;
1606-
Expr*raw_expr;/*raw expression */
1607-
Expr*formatted_expr;/* formatted expression */
1610+
Expr*raw_expr;/*user-specified expression */
1611+
Expr*formatted_expr;/*coercedformatted expression */
16081612
JsonFormat*format;/* FORMAT clause, if specified */
16091613
}JsonValueExpr;
16101614

‎src/test/regress/expected/sqljson.out

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,3 +951,52 @@ CREATE OR REPLACE VIEW public.is_json_view AS
951951
'{}'::text IS JSON OBJECT WITH UNIQUE KEYS AS object
952952
FROM generate_series(1, 3) i(i)
953953
DROP VIEW is_json_view;
954+
-- Bug #18657: JsonValueExpr.raw_expr was not initialized in ExecInitExprRec()
955+
-- causing the Aggrefs contained in it to also not be initialized, which led
956+
-- to a crash in ExecBuildAggTrans() as mentioned in the bug report:
957+
-- https://postgr.es/m/18657-1b90ccce2b16bdb8@postgresql.org
958+
CREATE FUNCTION volatile_one() RETURNS int AS $$ BEGIN RETURN 1; END; $$ LANGUAGE plpgsql VOLATILE;
959+
CREATE FUNCTION stable_one() RETURNS int AS $$ BEGIN RETURN 1; END; $$ LANGUAGE plpgsql STABLE;
960+
EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': volatile_one() RETURNING text) FORMAT JSON);
961+
QUERY PLAN
962+
-------------------------------------------------------------------------------------------------------------
963+
Aggregate
964+
Output: JSON_OBJECT('a' : JSON_OBJECTAGG('b' : volatile_one() RETURNING text) FORMAT JSON RETURNING json)
965+
-> Result
966+
(3 rows)
967+
968+
SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': volatile_one() RETURNING text) FORMAT JSON);
969+
json_object
970+
---------------------
971+
{"a" : { "b" : 1 }}
972+
(1 row)
973+
974+
EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': stable_one() RETURNING text) FORMAT JSON);
975+
QUERY PLAN
976+
-----------------------------------------------------------------------------------------------------------
977+
Aggregate
978+
Output: JSON_OBJECT('a' : JSON_OBJECTAGG('b' : stable_one() RETURNING text) FORMAT JSON RETURNING json)
979+
-> Result
980+
(3 rows)
981+
982+
SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': stable_one() RETURNING text) FORMAT JSON);
983+
json_object
984+
---------------------
985+
{"a" : { "b" : 1 }}
986+
(1 row)
987+
988+
EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': 1 RETURNING text) FORMAT JSON);
989+
QUERY PLAN
990+
------------------------------------------------------------------------------------------------
991+
Aggregate
992+
Output: JSON_OBJECT('a' : JSON_OBJECTAGG('b' : 1 RETURNING text) FORMAT JSON RETURNING json)
993+
-> Result
994+
(3 rows)
995+
996+
SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': 1 RETURNING text) FORMAT JSON);
997+
json_object
998+
---------------------
999+
{"a" : { "b" : 1 }}
1000+
(1 row)
1001+
1002+
DROP FUNCTION volatile_one, stable_one;

‎src/test/regress/sql/sqljson.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,17 @@ SELECT '1' IS JSON AS "any", ('1' || i) IS JSON SCALAR AS "scalar", '[]' IS NOT
383383
\sv is_json_view
384384

385385
DROPVIEW is_json_view;
386+
387+
-- Bug #18657: JsonValueExpr.raw_expr was not initialized in ExecInitExprRec()
388+
-- causing the Aggrefs contained in it to also not be initialized, which led
389+
-- to a crash in ExecBuildAggTrans() as mentioned in the bug report:
390+
-- https://postgr.es/m/18657-1b90ccce2b16bdb8@postgresql.org
391+
CREATEFUNCTIONvolatile_one() RETURNSintAS $$BEGIN RETURN1; END; $$ LANGUAGE plpgsql VOLATILE;
392+
CREATEFUNCTIONstable_one() RETURNSintAS $$BEGIN RETURN1; END; $$ LANGUAGE plpgsql STABLE;
393+
EXPLAIN (VERBOSE, COSTS OFF)SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': volatile_one() RETURNINGtext) FORMAT JSON);
394+
SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': volatile_one() RETURNINGtext) FORMAT JSON);
395+
EXPLAIN (VERBOSE, COSTS OFF)SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': stable_one() RETURNINGtext) FORMAT JSON);
396+
SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b': stable_one() RETURNINGtext) FORMAT JSON);
397+
EXPLAIN (VERBOSE, COSTS OFF)SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b':1 RETURNINGtext) FORMAT JSON);
398+
SELECT JSON_OBJECT('a': JSON_OBJECTAGG('b':1 RETURNINGtext) FORMAT JSON);
399+
DROPFUNCTION volatile_one, stable_one;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp