0001-Fix-assertion-failure-in-WAIT-FOR-LSN-when-used-insi.patch
application/octet-stream
Filename: 0001-Fix-assertion-failure-in-WAIT-FOR-LSN-when-used-insi.patch
Type: application/octet-stream
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v1-0001
Subject: Fix assertion failure in WAIT FOR LSN when used inside PL/pgSQL
| File | + | − |
|---|---|---|
| src/backend/commands/wait.c | 11 | 0 |
From 16ace60f82062f0f13fc1814085b045aedd6f202 Mon Sep 17 00:00:00 2001
From: Satya Narlapuram <satyanarlapuram@gmail.com>
Date: Thu, 9 Apr 2026 00:50:20 +0000
Subject: [PATCH v1 1/2] Fix assertion failure in WAIT FOR LSN when used inside
PL/pgSQL
WAIT FOR LSN ... INTO inside a DO block crashed with an assertion failure in
EnsurePortalSnapshotExists():
TRAP: failed Assert("portal->portalSnapshot == NULL"),
File: "pquery.c", Line: 1776
The root cause was that ExecWaitStmt() called PopActiveSnapshot() to
release the snapshot before waiting, but did not clear the active
portal's portalSnapshot pointer. When the next PL/pgSQL statement
requiring a snapshot called EnsurePortalSnapshotExists(), it found
a stale non-NULL portalSnapshot and hit the assertion.
PortalRunUtility() normally handles this cleanup in the top-level
execution path, but when WAIT FOR runs through SPI (PL/pgSQL),
ProcessUtility is called directly without the PortalRunUtility
wrapper, so the portalSnapshot was never cleared.
Fix by clearing ActivePortal->portalSnapshot after PopActiveSnapshot()
in ExecWaitStmt(), matching what PortalRunUtility() does.
---
src/backend/commands/wait.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/backend/commands/wait.c b/src/backend/commands/wait.c
index 85fcd463..8d245dbd 100644
--- a/src/backend/commands/wait.c
+++ b/src/backend/commands/wait.c
@@ -24,6 +24,7 @@
#include "executor/executor.h"
#include "parser/parse_node.h"
#include "storage/proc.h"
+#include "tcop/pquery.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/pg_lsn.h"
@@ -146,10 +147,20 @@ ExecWaitStmt(ParseState *pstate, WaitStmt *stmt, DestReceiver *dest)
* PlannedStmtRequiresSnapshot(), even in an atomic context, CallStmt is
* processed with a snapshot. Thankfully, we can pop this snapshot,
* because PortalRunUtility() can tolerate this.
+ *
+ * When running inside PL/pgSQL, the active
+ * portal may hold a pointer to this snapshot in portalSnapshot. We must
+ * clear it so that EnsurePortalSnapshotExists() doesn't trip an assertion
+ * when the next PL/pgSQL statement tries to re-establish a snapshot.
*/
if (ActiveSnapshotSet())
+ {
PopActiveSnapshot();
+ if (ActivePortal && ActivePortal->portalSnapshot != NULL)
+ ActivePortal->portalSnapshot = NULL;
+ }
+
/*
* At second, invalidate a catalog snapshot if any. And we should be done
* with the preparation.
--
2.43.0