aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/spi.c2
-rw-r--r--src/pl/plpgsql/src/pl_exec.c26
2 files changed, 16 insertions, 12 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index e516c0a67c6..d6516b1bca3 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -2044,6 +2044,8 @@ SPI_result_code_string(int code)
* SPI_plan_get_plan_sources --- get a SPI plan's underlying list of
* CachedPlanSources.
*
+ * CAUTION: there is no check on whether the CachedPlanSources are up-to-date.
+ *
* This is exported so that PL/pgSQL can use it (this beats letting PL/pgSQL
* look directly into the SPIPlan for itself). It's not documented in
* spi.sgml because we'd just as soon not have too many places using this.
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 239b3250a95..ea9740e3f89 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2276,8 +2276,8 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
static PLpgSQL_variable *
make_callstmt_target(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
{
- List *plansources;
- CachedPlanSource *plansource;
+ CachedPlan *cplan;
+ PlannedStmt *pstmt;
CallStmt *stmt;
FuncExpr *funcexpr;
HeapTuple func_tuple;
@@ -2294,16 +2294,15 @@ make_callstmt_target(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
/*
- * Get the parsed CallStmt, and look up the called procedure
+ * Get the parsed CallStmt, and look up the called procedure. We use
+ * SPI_plan_get_cached_plan to cover the edge case where expr->plan is
+ * already stale and needs to be updated.
*/
- plansources = SPI_plan_get_plan_sources(expr->plan);
- if (list_length(plansources) != 1)
- elog(ERROR, "query for CALL statement is not a CallStmt");
- plansource = (CachedPlanSource *) linitial(plansources);
- if (list_length(plansource->query_list) != 1)
+ cplan = SPI_plan_get_cached_plan(expr->plan);
+ if (cplan == NULL || list_length(cplan->stmt_list) != 1)
elog(ERROR, "query for CALL statement is not a CallStmt");
- stmt = (CallStmt *) linitial_node(Query,
- plansource->query_list)->utilityStmt;
+ pstmt = linitial_node(PlannedStmt, cplan->stmt_list);
+ stmt = (CallStmt *) pstmt->utilityStmt;
if (stmt == NULL || !IsA(stmt, CallStmt))
elog(ERROR, "query for CALL statement is not a CallStmt");
@@ -2383,6 +2382,8 @@ make_callstmt_target(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
row->nfields = nfields;
+ ReleaseCachedPlan(cplan, CurrentResourceOwner);
+
MemoryContextSwitchTo(oldcontext);
return (PLpgSQL_variable *) row;
@@ -4245,8 +4246,9 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
/*
* We could look at the raw_parse_tree, but it seems simpler to
* check the command tag. Note we should *not* look at the Query
- * tree(s), since those are the result of rewriting and could have
- * been transmogrified into something else entirely.
+ * tree(s), since those are the result of rewriting and could be
+ * stale, or could have been transmogrified into something else
+ * entirely.
*/
if (plansource->commandTag == CMDTAG_INSERT ||
plansource->commandTag == CMDTAG_UPDATE ||