Skip to content

Commit b998655

Browse files
committed
Fix plan cache issue in PL/pgSQL CALL
If we are not going to save the plan, then we need to unset expr->plan after we are done, also in error cases. Otherwise, we get a dangling pointer next time around. This is not the ideal solution. It would be better if we could convince SPI not to associate a cached plan with a resource owner, and then we could just save the plan in all cases. But that would require bigger surgery. Reported-by: Pavel Stehule <pavel.stehule@gmail.com>
1 parent 6a5f796 commit b998655

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

src/pl/plpgsql/src/expected/plpgsql_call.out

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ SELECT * FROM test1;
5353
66
5454
(2 rows)
5555

56+
CALL test_proc4(66);
57+
SELECT * FROM test1;
58+
a
59+
----
60+
66
61+
66
62+
66
63+
66
64+
(4 rows)
65+
5666
-- output arguments
5767
CREATE PROCEDURE test_proc5(INOUT a text)
5868
LANGUAGE plpgsql

src/pl/plpgsql/src/pl_exec.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,7 @@ static int
20602060
exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
20612061
{
20622062
PLpgSQL_expr *expr = stmt->expr;
2063+
SPIPlanPtr plan;
20632064
ParamListInfo paramLI;
20642065
LocalTransactionId before_lxid;
20652066
LocalTransactionId after_lxid;
@@ -2069,7 +2070,9 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
20692070
{
20702071
/*
20712072
* Don't save the plan if not in atomic context. Otherwise,
2072-
* transaction ends would cause warnings about plan leaks.
2073+
* transaction ends would cause errors about plancache leaks. XXX
2074+
* This would be fixable with some plancache/resowner surgery
2075+
* elsewhere, but for now we'll just work around this here.
20732076
*/
20742077
exec_prepare_plan(estate, expr, 0, estate->atomic);
20752078

@@ -2084,8 +2087,27 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
20842087

20852088
before_lxid = MyProc->lxid;
20862089

2087-
rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
2088-
estate->readonly_func, 0);
2090+
PG_TRY();
2091+
{
2092+
rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
2093+
estate->readonly_func, 0);
2094+
}
2095+
PG_CATCH();
2096+
{
2097+
/*
2098+
* If we aren't saving the plan, unset the pointer. Note that it
2099+
* could have been unset already, in case of a recursive call.
2100+
*/
2101+
if (expr->plan && !expr->plan->saved)
2102+
expr->plan = NULL;
2103+
PG_RE_THROW();
2104+
}
2105+
PG_END_TRY();
2106+
2107+
plan = expr->plan;
2108+
2109+
if (expr->plan && !expr->plan->saved)
2110+
expr->plan = NULL;
20892111

20902112
after_lxid = MyProc->lxid;
20912113

@@ -2129,7 +2151,7 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
21292151
/*
21302152
* Get the original CallStmt
21312153
*/
2132-
node = linitial_node(Query, ((CachedPlanSource *) linitial(expr->plan->plancache_list))->query_list)->utilityStmt;
2154+
node = linitial_node(Query, ((CachedPlanSource *) linitial(plan->plancache_list))->query_list)->utilityStmt;
21332155
if (!IsA(node, CallStmt))
21342156
elog(ERROR, "returned row from not a CallStmt");
21352157

src/pl/plpgsql/src/sql/plpgsql_call.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ CALL test_proc4(66);
5454

5555
SELECT * FROM test1;
5656

57+
CALL test_proc4(66);
58+
59+
SELECT * FROM test1;
60+
5761

5862
-- output arguments
5963

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy