Fix concurrent update issue with MERGE.
authorDean Rasheed <dean.a.rasheed@gmail.com>
Fri, 5 Sep 2025 07:18:18 +0000 (08:18 +0100)
committerDean Rasheed <dean.a.rasheed@gmail.com>
Fri, 5 Sep 2025 07:18:18 +0000 (08:18 +0100)
commit6ede13d1b5f515df0a199a7a830e448dab1511c0
tree9bb5fc275c742607713acb7f3effca60dcb9e042
parent567d27e8e2b752743626eb259ba75ecdc936eaf3
Fix concurrent update issue with MERGE.

When executing a MERGE UPDATE action, if there is more than one
concurrent update of the target row, the lock-and-retry code would
sometimes incorrectly identify the latest version of the target tuple,
leading to incorrect results.

This was caused by using the ctid field from the TM_FailureData
returned by table_tuple_lock() in a case where the result was TM_Ok,
which is unsafe because the TM_FailureData struct is not guaranteed to
be fully populated in that case. Instead, it should use the tupleid
passed to (and updated by) table_tuple_lock().

To reduce the chances of similar errors in the future, improve the
commentary for table_tuple_lock() and TM_FailureData to make it
clearer that table_tuple_lock() updates the tid passed to it, and most
fields of TM_FailureData should not be relied on in non-failure cases.
An exception to this is the "traversed" field, which is set in both
success and failure cases.

Reported-by: Dmitry <dsy.075@yandex.ru>
Author: Yugo Nagata <nagata@sraoss.co.jp>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/1570d30e-2b95-4239-b9c3-f7bf2f2f8556@yandex.ru
Backpatch-through: 15
src/backend/executor/nodeModifyTable.c
src/include/access/tableam.h
src/test/isolation/expected/merge-match-recheck.out
src/test/isolation/specs/merge-match-recheck.spec