Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2e78c5b

Browse files
committed
Fix assert in nested SQL procedure call
When executing CALL in PL/pgSQL, we need to set a snapshot beforeinvoking the to-be-called procedure. Otherwise, the to-be-calledprocedure might end up running without a snapshot. For LANGUAGE SQLprocedures, this would result in an assertion failure. (For most otherlanguages, this is usually not a problem, because those use SPI and SPIsets snapshots in most cases.) Setting the snapshot restores thebehavior of how CALL worked when it was handled as a generic SQLstatement in PL/pgSQL (exec_stmt_execsql()).This change revealed another problem: In SPI_commit(), we popped theactive snapshot before committing the transaction, to avoid "snapshot %pstill active" errors. However, there is no particular reason why onlyat most one snapshot should be on the stack. So change this to pop allactive snapshots instead of only one.
1 parente34ec13 commit2e78c5b

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

‎src/backend/executor/spi.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,13 @@ SPI_commit(void)
228228

229229
_SPI_current->internal_xact= true;
230230

231-
if (ActiveSnapshotSet())
231+
/*
232+
* Before committing, pop all active snapshots to avoid error about
233+
* "snapshot %p still active".
234+
*/
235+
while (ActiveSnapshotSet())
232236
PopActiveSnapshot();
237+
233238
CommitTransactionCommand();
234239
MemoryContextSwitchTo(oldcontext);
235240

‎src/pl/plpgsql/src/expected/plpgsql_transaction.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,25 @@ END;
432432
$$;
433433
ERROR: EXECUTE of transaction commands is not implemented
434434
CONTEXT: PL/pgSQL function inline_code_block line 3 at EXECUTE
435+
-- snapshot handling test
436+
TRUNCATE test2;
437+
CREATE PROCEDURE transaction_test9()
438+
LANGUAGE SQL
439+
AS $$
440+
INSERT INTO test2 VALUES (42);
441+
$$;
442+
DO LANGUAGE plpgsql $$
443+
BEGIN
444+
ROLLBACK;
445+
CALL transaction_test9();
446+
END
447+
$$;
448+
SELECT * FROM test2;
449+
x
450+
----
451+
42
452+
(1 row)
453+
435454
DROP TABLE test1;
436455
DROP TABLE test2;
437456
DROP TABLE test3;

‎src/pl/plpgsql/src/pl_exec.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,6 +2075,7 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
20752075
ParamListInfoparamLI;
20762076
LocalTransactionIdbefore_lxid;
20772077
LocalTransactionIdafter_lxid;
2078+
boolpushed_active_snap= false;
20782079
intrc;
20792080

20802081
if (expr->plan==NULL)
@@ -2090,6 +2091,7 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
20902091
/*
20912092
* The procedure call could end transactions, which would upset the
20922093
* snapshot management in SPI_execute*, so don't let it do it.
2094+
* Instead, we set the snapshots ourselves below.
20932095
*/
20942096
expr->plan->no_snapshots= true;
20952097
}
@@ -2098,6 +2100,16 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
20982100

20992101
before_lxid=MyProc->lxid;
21002102

2103+
/*
2104+
* Set snapshot only for non-read-only procedures, similar to SPI
2105+
* behavior.
2106+
*/
2107+
if (!estate->readonly_func)
2108+
{
2109+
PushActiveSnapshot(GetTransactionSnapshot());
2110+
pushed_active_snap= true;
2111+
}
2112+
21012113
PG_TRY();
21022114
{
21032115
rc=SPI_execute_plan_with_paramlist(expr->plan,paramLI,
@@ -2126,12 +2138,22 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
21262138
elog(ERROR,"SPI_execute_plan_with_paramlist failed executing query \"%s\": %s",
21272139
expr->query,SPI_result_code_string(rc));
21282140

2129-
/*
2130-
* If we are in a new transaction after the call, we need to reset some
2131-
* internal state.
2132-
*/
2133-
if (before_lxid!=after_lxid)
2141+
if (before_lxid==after_lxid)
2142+
{
2143+
/*
2144+
* If we are still in the same transaction after the call, pop the
2145+
* snapshot that we might have pushed. (If it's a new transaction,
2146+
* then all the snapshots are gone already.)
2147+
*/
2148+
if (pushed_active_snap)
2149+
PopActiveSnapshot();
2150+
}
2151+
else
21342152
{
2153+
/*
2154+
* If we are in a new transaction after the call, we need to reset
2155+
* some internal state.
2156+
*/
21352157
estate->simple_eval_estate=NULL;
21362158
plpgsql_create_econtext(estate);
21372159
}

‎src/pl/plpgsql/src/sql/plpgsql_transaction.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,26 @@ BEGIN
354354
END;
355355
$$;
356356

357+
358+
-- snapshot handling test
359+
TRUNCATE test2;
360+
361+
CREATE PROCEDURE transaction_test9()
362+
LANGUAGE SQL
363+
AS $$
364+
INSERT INTO test2VALUES (42);
365+
$$;
366+
367+
DO LANGUAGE plpgsql $$
368+
BEGIN
369+
ROLLBACK;
370+
CALL transaction_test9();
371+
END
372+
$$;
373+
374+
SELECT*FROM test2;
375+
376+
357377
DROPTABLE test1;
358378
DROPTABLE test2;
359379
DROPTABLE test3;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp