From e88a42f4832a015ab185bc2edd48f986f6fbdc2e Mon Sep 17 00:00:00 2001 From: Sami Imseih Date: Tue, 8 Sep 2026 19:34:13 +0000 Subject: [PATCH v1 1/1] Reject WAIT FOR earlier in transaction-snapshot mode The documentation says that WAIT FOR cannot be used in transactions above READ COMMITTED, but the implementation only rejected it after a transaction snapshot had already been taken. Make WAIT FOR fail earlier in transaction-snapshot mode so the behavior matches the documented restriction and the intended invariant. Add a recovery test that covers the REPEATABLE READ case before any statement has forced the transaction snapshot. --- src/backend/commands/wait.c | 9 +++++++-- src/test/recovery/t/049_wait_for_lsn.pl | 14 +++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/backend/commands/wait.c b/src/backend/commands/wait.c index 9ba4c75021e..7d8f41e2736 100644 --- a/src/backend/commands/wait.c +++ b/src/backend/commands/wait.c @@ -15,6 +15,7 @@ #include +#include "access/xact.h" #include "access/xlog.h" #include "access/xlogrecovery.h" #include "access/xlogwait.h" @@ -167,8 +168,12 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, bool isTopLevel, */ InvalidateCatalogSnapshot(); - /* Give up if there is still an active or registered snapshot. */ - if (HaveRegisteredOrActiveSnapshot()) + /* + * Give up if there is still an active or registered snapshot. Also reject + * transactions that use a transaction snapshot, even if that snapshot has + * not been taken yet. + */ + if (HaveRegisteredOrActiveSnapshot() || IsolationUsesXactSnapshot()) ereport(ERROR, errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("WAIT FOR must be called without an active or registered snapshot"), diff --git a/src/test/recovery/t/049_wait_for_lsn.pl b/src/test/recovery/t/049_wait_for_lsn.pl index cb7d4d461de..5faabc8b0a3 100644 --- a/src/test/recovery/t/049_wait_for_lsn.pl +++ b/src/test/recovery/t/049_wait_for_lsn.pl @@ -264,7 +264,7 @@ unlike( # 5. Check mode validation: standby modes error on primary, primary mode errors # on standby, and primary_flush works on primary. Also check that WAIT FOR # triggers an error if called within a function, procedure, anonymous DO block, -# or inside a transaction with an isolation level higher than READ COMMITTED. +# or inside a transaction that uses a transaction snapshot. # Test standby_flush on primary - should error $node_primary->psql( @@ -291,6 +291,18 @@ ok( $stderr =~ "get an error when running in a transaction with an isolation level higher than REPEATABLE READ" ); +$node_standby->psql( + 'postgres', + qq[ +BEGIN ISOLATION LEVEL REPEATABLE READ; +WAIT FOR LSN '${lsn3}' WITH (MODE 'primary_flush'); +], + stderr => \$stderr); +ok( $stderr =~ + /WAIT FOR must be called without an active or registered snapshot/, + "get an error before taking a repeatable read transaction snapshot" +); + # Test wrapping WAIT FOR into function, procedure, and anonymous DO block -- # should error $node_primary->safe_psql( -- 2.50.1