From 4eb0f045b918325bb20d23c34fa2ec007b25b379 Mon Sep 17 00:00:00 2001
From: Yugo Nagata <nagata@sraoss.co.jp>
Date: Mon, 25 Aug 2025 01:57:25 +0900
Subject: [PATCH] Fix misuse of TM_FailureData.ctid in ExecMergeMatched

Previously, the ctid field of TM_FailureData returned by table_tuple_lock()
was used as a reference to the latest version of oldtuple, but
this was not always correct. Instead, the tupleid passed to
table_tuple_lock() should be used.

This misuse caused incorrect UPDATE results when more than two
MERGE commands were executed concurrently.
---
 src/backend/executor/nodeModifyTable.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 7c6c2c1f6e4..ea1457ce3bf 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -3450,12 +3450,13 @@ lmerge_matched:
 									if (ItemPointerIsValid(&lockedtid))
 										UnlockTuple(resultRelInfo->ri_RelationDesc, &lockedtid,
 													InplaceUpdateTupleLock);
-									LockTuple(resultRelInfo->ri_RelationDesc, &context->tmfd.ctid,
+									LockTuple(resultRelInfo->ri_RelationDesc, tupleid,
 											  InplaceUpdateTupleLock);
-									lockedtid = context->tmfd.ctid;
+									lockedtid = *tupleid;
 								}
+
 								if (!table_tuple_fetch_row_version(resultRelationDesc,
-																   &context->tmfd.ctid,
+																   tupleid,
 																   SnapshotAny,
 																   resultRelInfo->ri_oldTupleSlot))
 									elog(ERROR, "failed to fetch the target tuple");
-- 
2.43.0

