From dd642a2293e09ae1b559c1b73a053f3fd33bc68f Mon Sep 17 00:00:00 2001
From: Vaijayanti Bharadwaj <vaijayanti.bharadwaj@enterprisedb.com>
Date: Tue, 27 Oct 2026 22:07:22 +0530
Subject: [PATCH v2 1/2] Fix concurrent-abort detection for subtransactions of
 prepared xacts

When decoding a prepared transaction at PREPARE time,
ReorderBufferProcessTXN() is supposed to set CheckXidAlive for each
change, so that a catalog scan notices if the transaction is rolled back
concurrently.  The condition tested rbtxn_is_prepared() on the change's
own ReorderBufferTXN, but RBTXN_IS_PREPARED is only set on the top-level
transaction.  Changes made in the first subtransaction therefore
never set CheckXidAlive.

If such a transaction made a catalog change and then DML inside a
subtransaction, and was rolled back with ROLLBACK PREPARED while being
decoded, the decoder could go on using catalog tuples whose xmax had been
overwritten by a later transaction, and decode the DML with the wrong
catalog version.

Fix is to test the flag on the top-level transaction instead.
CheckXidAlive is still set to the subtransaction's xid, which aborts
together with its parent once the transaction is prepared.

Backpatch-through: 14
---
 src/backend/replication/logical/reorderbuffer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 6c4eadc9972..b8b3efed946 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -2305,7 +2305,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * required for the cases when we decode the changes before the
 			 * COMMIT record is processed.
 			 */
-			if (streaming || rbtxn_is_prepared(change->txn))
+			if (streaming || rbtxn_is_prepared(txn))
 			{
 				curtxn = change->txn;
 				SetupCheckXidLive(curtxn->xid);
-- 
2.55.0

