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;
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");
row->nfields = nfields;
+ ReleaseCachedPlan(cplan, CurrentResourceOwner);
+
MemoryContextSwitchTo(oldcontext);
return (PLpgSQL_variable *) row;
/*
* 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 ||