From 50beec4de4e078020b03667453458cd440c26267 Mon Sep 17 00:00:00 2001 From: alterego655 <824662526@qq.com> Date: Mon, 12 Jan 2026 14:36:27 +0800 Subject: [PATCH v1] Avoid syscache lookup in WAIT FOR LSN tuple descriptor Use TupleDescInitBuiltinEntry instead of TupleDescInitEntry when building the result tuple descriptor for WAIT FOR LSN. This avoids a syscache access that could re-establish a catalog snapshot after we've explicitly released all snapshots before the wait. --- src/backend/commands/wait.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/wait.c b/src/backend/commands/wait.c index 97f1e778488..191c1877125 100644 --- a/src/backend/commands/wait.c +++ b/src/backend/commands/wait.c @@ -15,6 +15,7 @@ #include +#include "access/tupdesc.h" #include "access/xlog.h" #include "access/xlogrecovery.h" #include "access/xlogwait.h" @@ -320,7 +321,17 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, DestReceiver *dest) break; } - /* need a tuple descriptor representing a single TEXT column */ + /* + * Output the result. + * + * We use TupleDescInitBuiltinEntry in WaitStmtResultDesc to avoid + * syscache access when building the tuple descriptor. The standard output + * path may briefly establish a catalog snapshot during output, but this + * is acceptable since: 1. The snapshot window is very brief (just + * emitting one row) 2. The critical section (the wait itself) is already + * snapshot-free 3. Using the standard path respects receiver lifecycle + * and semantics + */ tupdesc = WaitStmtResultDesc(stmt); /* prepare for projection of tuples */ @@ -337,9 +348,16 @@ WaitStmtResultDesc(WaitStmt *stmt) { TupleDesc tupdesc; - /* Need a tuple descriptor representing a single TEXT column */ + /* + * Need a tuple descriptor representing a single TEXT column. + * + * We use TupleDescInitBuiltinEntry instead of TupleDescInitEntry to avoid + * syscache access. This is important because WaitStmtResultDesc may be + * called after snapshots have been released, and we must not re-establish + * a catalog snapshot which could cause recovery conflicts on a standby. + */ tupdesc = CreateTemplateTupleDesc(1); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status", - TEXTOID, -1, 0); + TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "status", + TEXTOID, -1, 0); return tupdesc; } -- 2.51.0