Skip to content

Commit f26c06a

Browse files
committed
Fix error-cleanup mistakes in exec_stmt_call().
Commit 15c7293 was a couple bricks shy of a load: we need to ensure that expr->plan gets reset to NULL on any error exit, if it's not supposed to be saved. Also ensure that the stmt->target calculation gets redone if needed. The easy way to exhibit a problem is to set up code that violates the writable-argument restriction and then execute it twice. But error exits out of, eg, setup_param_list() could also break it. Make the existing PG_TRY block cover all of that code to be sure. Per report from Pavel Stehule. Discussion: https://postgr.es/m/CAFj8pRAeXNTO43W2Y0Cn0YOVFPv1WpYyOqQrrzUiN6s=dn7gCg@mail.gmail.com
1 parent fa2952d commit f26c06a

File tree

1 file changed

+45
-37
lines changed

1 file changed

+45
-37
lines changed

src/pl/plpgsql/src/pl_exec.c

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,39 +2072,50 @@ static int
20722072
exec_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

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