@@ -2072,39 +2072,50 @@ static int
20722072exec_stmt_call (PLpgSQL_execstate * estate , PLpgSQL_stmt_call * stmt )
20732073{
20742074 PLpgSQL_expr * expr = stmt -> expr ;
2075- ParamListInfo paramLI ;
2076- LocalTransactionId before_lxid ;
2075+ volatile LocalTransactionId before_lxid ;
20772076 LocalTransactionId after_lxid ;
2078- bool pushed_active_snap = false;
2079- int rc ;
2077+ volatile bool pushed_active_snap = false;
2078+ volatile int rc ;
20802079
2081- if (expr -> plan == NULL )
2080+ /* PG_TRY to ensure we clear the plan link, if needed, on failure */
2081+ PG_TRY ();
20822082 {
2083- SPIPlanPtr plan ;
2083+ SPIPlanPtr plan = expr -> plan ;
2084+ ParamListInfo paramLI ;
20842085
2085- /*
2086- * Don't save the plan if not in atomic context. Otherwise,
2087- * transaction ends would cause errors about plancache leaks. XXX
2088- * This would be fixable with some plancache/resowner surgery
2089- * elsewhere, but for now we'll just work around this here.
2090- */
2091- exec_prepare_plan (estate , expr , 0 , estate -> atomic );
2086+ if (plan == NULL )
2087+ {
20922088
2093- /*
2094- * The procedure call could end transactions, which would upset the
2095- * snapshot management in SPI_execute*, so don't let it do it.
2096- * Instead, we set the snapshots ourselves below.
2097- */
2098- plan = expr -> plan ;
2099- plan -> no_snapshots = true;
2089+ /*
2090+ * Don't save the plan if not in atomic context. Otherwise,
2091+ * transaction ends would cause errors about plancache leaks.
2092+ *
2093+ * XXX This would be fixable with some plancache/resowner surgery
2094+ * elsewhere, but for now we'll just work around this here.
2095+ */
2096+ exec_prepare_plan (estate , expr , 0 , estate -> atomic );
2097+
2098+ /*
2099+ * The procedure call could end transactions, which would upset
2100+ * the snapshot management in SPI_execute*, so don't let it do it.
2101+ * Instead, we set the snapshots ourselves below.
2102+ */
2103+ plan = expr -> plan ;
2104+ plan -> no_snapshots = true;
2105+
2106+ /*
2107+ * Force target to be recalculated whenever the plan changes, in
2108+ * case the procedure's argument list has changed.
2109+ */
2110+ stmt -> target = NULL ;
2111+ }
21002112
21012113 /*
21022114 * We construct a DTYPE_ROW datum representing the plpgsql variables
21032115 * associated with the procedure's output arguments. Then we can use
2104- * exec_move_row() to do the assignments. (We do this each time the
2105- * plan changes, in case the procedure's argument list has changed.)
2116+ * exec_move_row() to do the assignments.
21062117 */
2107- if (stmt -> is_call )
2118+ if (stmt -> is_call && stmt -> target == NULL )
21082119 {
21092120 Node * node ;
21102121 FuncExpr * funcexpr ;
@@ -2206,24 +2217,21 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
22062217
22072218 stmt -> target = (PLpgSQL_variable * ) row ;
22082219 }
2209- }
22102220
2211- paramLI = setup_param_list (estate , expr );
2221+ paramLI = setup_param_list (estate , expr );
22122222
2213- before_lxid = MyProc -> lxid ;
2223+ before_lxid = MyProc -> lxid ;
22142224
2215- /*
2216- * Set snapshot only for non-read-only procedures, similar to SPI
2217- * behavior.
2218- */
2219- if (!estate -> readonly_func )
2220- {
2221- PushActiveSnapshot (GetTransactionSnapshot ());
2222- pushed_active_snap = true;
2223- }
2225+ /*
2226+ * Set snapshot only for non-read-only procedures, similar to SPI
2227+ * behavior.
2228+ */
2229+ if (!estate -> readonly_func )
2230+ {
2231+ PushActiveSnapshot (GetTransactionSnapshot ());
2232+ pushed_active_snap = true;
2233+ }
22242234
2225- PG_TRY ();
2226- {
22272235 rc = SPI_execute_plan_with_paramlist (expr -> plan , paramLI ,
22282236 estate -> readonly_func , 0 );
22292237 }
0 commit comments