mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Don't let JSON constructor coercions block SQL function inlining
contain_context_dependent_node_walker() reports a CaseTestExpr as context-dependent unless it sits under a simple CaseExpr or the elemexpr of an ArrayCoerceExpr. A JsonConstructorExpr whose RETURNING type requires a coercion also carries a CaseTestExpr placeholder in that coercion, so any SQL function called with such a constructor as an argument was refused inlining. Teach the walker that a CaseTestExpr is expected within the coercion of a JsonConstructorExpr, the same way it already handles the elemexpr of an ArrayCoerceExpr. This is safe now that eval_const_expressions no longer lets an enclosing simple CASE clobber that placeholder. Author: Richard Guo <guofenglinux@gmail.com> Discussion: https://postgr.es/m/CAMbWs48A=VCFbteTkuCoknO1_0-Cu0aMBT0M07dm7vj1QyixDg@mail.gmail.com Backpatch-through: 19
This commit is contained in:
@@ -1255,7 +1255,8 @@ contain_exec_param_walker(Node *node, List *param_ids)
|
||||
* not nested within another one, or they'll see the wrong test value. If one
|
||||
* appears "bare" in the arguments of a SQL function, then we can't inline the
|
||||
* SQL function for fear of creating such a situation. The same applies for
|
||||
* CaseTestExpr used within the elemexpr of an ArrayCoerceExpr.
|
||||
* CaseTestExpr used within the elemexpr of an ArrayCoerceExpr or the coercion
|
||||
* of a JsonConstructorExpr.
|
||||
*
|
||||
* CoerceToDomainValue would have the same issue if domain CHECK expressions
|
||||
* could get inlined into larger expressions, but presently that's impossible.
|
||||
@@ -1328,6 +1329,26 @@ contain_context_dependent_node_walker(Node *node, int *flags)
|
||||
*flags = save_flags;
|
||||
return res;
|
||||
}
|
||||
else if (IsA(node, JsonConstructorExpr))
|
||||
{
|
||||
JsonConstructorExpr *jce = (JsonConstructorExpr *) node;
|
||||
int save_flags;
|
||||
bool res;
|
||||
|
||||
/* Check the args and func expressions */
|
||||
if (contain_context_dependent_node_walker((Node *) jce->args, flags))
|
||||
return true;
|
||||
if (contain_context_dependent_node_walker((Node *) jce->func, flags))
|
||||
return true;
|
||||
|
||||
/* Check the coercion, which is allowed to contain CaseTestExpr */
|
||||
save_flags = *flags;
|
||||
*flags |= CCDN_CASETESTEXPR_OK;
|
||||
res = contain_context_dependent_node_walker((Node *) jce->coercion,
|
||||
flags);
|
||||
*flags = save_flags;
|
||||
return res;
|
||||
}
|
||||
return expression_tree_walker(node, contain_context_dependent_node_walker,
|
||||
flags);
|
||||
}
|
||||
|
||||
@@ -580,6 +580,24 @@ SELECT CASE 'x' WHEN JSON_OBJECT('a': 'b' RETURNING text) THEN 1 ELSE 0 END;
|
||||
0
|
||||
(1 row)
|
||||
|
||||
-- the RETURNING coercion must not prevent inlining of a SQL function
|
||||
CREATE FUNCTION json_object_inline_test(text) RETURNS text
|
||||
LANGUAGE sql IMMUTABLE AS $$ SELECT $1 || '!' $$;
|
||||
EXPLAIN (VERBOSE, COSTS OFF)
|
||||
SELECT json_object_inline_test(JSON_OBJECT('a': 'b' RETURNING text));
|
||||
QUERY PLAN
|
||||
----------------------------------------------------------------------
|
||||
Result
|
||||
Output: (JSON_OBJECT('a' : 'b'::text RETURNING text) || '!'::text)
|
||||
(2 rows)
|
||||
|
||||
SELECT json_object_inline_test(JSON_OBJECT('a': 'b' RETURNING text));
|
||||
json_object_inline_test
|
||||
-------------------------
|
||||
{"a" : "b"}!
|
||||
(1 row)
|
||||
|
||||
DROP FUNCTION json_object_inline_test(text);
|
||||
-- BUG: https://postgr.es/m/CADXhmgTJtJZK9A3Na_ry%2BXrq-ghjcejBRhcRMzWZvbd__QdgJA%40mail.gmail.com
|
||||
-- datum_to_jsonb_internal() didn't catch keys that are casts instead of a simple scalar
|
||||
CREATE TYPE mood AS ENUM ('happy', 'sad', 'neutral');
|
||||
|
||||
@@ -155,6 +155,14 @@ SELECT JSON_OBJECT(1: 1, '2': NULL, '3': 1, 4: NULL, '5': 'a' ABSENT ON NULL WIT
|
||||
-- the RETURNING coercion must not pick up the test value of an enclosing CASE
|
||||
SELECT CASE 'x' WHEN JSON_OBJECT('a': 'b' RETURNING text) THEN 1 ELSE 0 END;
|
||||
|
||||
-- the RETURNING coercion must not prevent inlining of a SQL function
|
||||
CREATE FUNCTION json_object_inline_test(text) RETURNS text
|
||||
LANGUAGE sql IMMUTABLE AS $$ SELECT $1 || '!' $$;
|
||||
EXPLAIN (VERBOSE, COSTS OFF)
|
||||
SELECT json_object_inline_test(JSON_OBJECT('a': 'b' RETURNING text));
|
||||
SELECT json_object_inline_test(JSON_OBJECT('a': 'b' RETURNING text));
|
||||
DROP FUNCTION json_object_inline_test(text);
|
||||
|
||||
-- BUG: https://postgr.es/m/CADXhmgTJtJZK9A3Na_ry%2BXrq-ghjcejBRhcRMzWZvbd__QdgJA%40mail.gmail.com
|
||||
-- datum_to_jsonb_internal() didn't catch keys that are casts instead of a simple scalar
|
||||
CREATE TYPE mood AS ENUM ('happy', 'sad', 'neutral');
|
||||
|
||||
Reference in New Issue
Block a user