mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-03 01:46:57 +02:00
Collect dependency information for parsed CallStmts.
Parse analysis of a CallStmt will inject mutable information,
for instance the OID of the called procedure, so that subsequent
DDL may create a need to re-parse the CALL. We failed to detect
this for CALLs in plpgsql routines, because no dependency information
was collected when putting a CallStmt into the plan cache. That
could lead to misbehavior or strange errors such as "cache lookup
failed".
Before commit ee895a655
, the issue would only manifest for CALLs
appearing in atomic contexts, because we re-planned non-atomic
CALLs every time through anyway.
It is now apparent that extract_query_dependencies() probably
needs a special case for every utility statement type for which
stmt_requires_parse_analysis() returns true. I wanted to add
something like Assert(!stmt_requires_parse_analysis(...)) when
falling out of extract_query_dependencies_walker without doing
anything, but there are API issues as well as a more fundamental
point: stmt_requires_parse_analysis is supposed to be applied to
raw parser output, so it'd be cheating to assume it will give the
correct answer for post-parse-analysis trees. I contented myself
with adding a comment.
Per bug #18131 from Christian Stork. Back-patch to all supported
branches.
Discussion: https://postgr.es/m/18131-576854e79c5cd264@postgresql.org
This commit is contained in:
parent
4a81ed29d3
commit
4435a8d5db
@ -2856,8 +2856,25 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
|
||||
if (query->commandType == CMD_UTILITY)
|
||||
{
|
||||
/*
|
||||
* Ignore utility statements, except those (such as EXPLAIN) that
|
||||
* contain a parsed-but-not-planned query.
|
||||
* This logic must handle any utility command for which parse
|
||||
* analysis was nontrivial (cf. stmt_requires_parse_analysis).
|
||||
*
|
||||
* Notably, CALL requires its own processing.
|
||||
*/
|
||||
if (IsA(query->utilityStmt, CallStmt))
|
||||
{
|
||||
CallStmt *callstmt = (CallStmt *) query->utilityStmt;
|
||||
|
||||
/* We need not examine funccall, just the transformed exprs */
|
||||
(void) extract_query_dependencies_walker((Node *) callstmt->funcexpr,
|
||||
context);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore other utility statements, except those (such as EXPLAIN)
|
||||
* that contain a parsed-but-not-planned query. For those, we
|
||||
* just need to transfer our attention to the contained query.
|
||||
*/
|
||||
query = UtilityContainsQuery(query->utilityStmt);
|
||||
if (query == NULL)
|
||||
|
@ -376,3 +376,50 @@ BEGIN
|
||||
END;
|
||||
$$;
|
||||
NOTICE: <NULL>
|
||||
-- check that we detect change of dependencies in CALL
|
||||
-- atomic and non-atomic call sites do this differently, so check both
|
||||
CREATE PROCEDURE inner_p (f1 int)
|
||||
AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'inner_p(%)', f1;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE FUNCTION f(int) RETURNS int AS $$ SELECT $1 + 1 $$ LANGUAGE sql;
|
||||
CREATE PROCEDURE outer_p (f1 int)
|
||||
AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'outer_p(%)', f1;
|
||||
CALL inner_p(f(f1));
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE FUNCTION outer_f (f1 int) RETURNS void
|
||||
AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'outer_f(%)', f1;
|
||||
CALL inner_p(f(f1));
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
CALL outer_p(42);
|
||||
NOTICE: outer_p(42)
|
||||
NOTICE: inner_p(43)
|
||||
SELECT outer_f(42);
|
||||
NOTICE: outer_f(42)
|
||||
NOTICE: inner_p(43)
|
||||
outer_f
|
||||
---------
|
||||
|
||||
(1 row)
|
||||
|
||||
DROP FUNCTION f(int);
|
||||
CREATE FUNCTION f(int) RETURNS int AS $$ SELECT $1 + 2 $$ LANGUAGE sql;
|
||||
CALL outer_p(42);
|
||||
NOTICE: outer_p(42)
|
||||
NOTICE: inner_p(44)
|
||||
SELECT outer_f(42);
|
||||
NOTICE: outer_f(42)
|
||||
NOTICE: inner_p(44)
|
||||
outer_f
|
||||
---------
|
||||
|
||||
(1 row)
|
||||
|
||||
|
@ -357,3 +357,41 @@ BEGIN
|
||||
RAISE NOTICE '%', v_Text;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
-- check that we detect change of dependencies in CALL
|
||||
-- atomic and non-atomic call sites do this differently, so check both
|
||||
|
||||
CREATE PROCEDURE inner_p (f1 int)
|
||||
AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'inner_p(%)', f1;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE FUNCTION f(int) RETURNS int AS $$ SELECT $1 + 1 $$ LANGUAGE sql;
|
||||
|
||||
CREATE PROCEDURE outer_p (f1 int)
|
||||
AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'outer_p(%)', f1;
|
||||
CALL inner_p(f(f1));
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE FUNCTION outer_f (f1 int) RETURNS void
|
||||
AS $$
|
||||
BEGIN
|
||||
RAISE NOTICE 'outer_f(%)', f1;
|
||||
CALL inner_p(f(f1));
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CALL outer_p(42);
|
||||
SELECT outer_f(42);
|
||||
|
||||
DROP FUNCTION f(int);
|
||||
CREATE FUNCTION f(int) RETURNS int AS $$ SELECT $1 + 2 $$ LANGUAGE sql;
|
||||
|
||||
CALL outer_p(42);
|
||||
SELECT outer_f(42);
|
||||
|
Loading…
Reference in New Issue
Block a user