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 <[email protected]> Author: Yugo Nagata <[email protected]> Reviewed-by: Dean Rasheed <[email protected]> Reviewed-by: Chao Li <[email protected]> Discussion: https://postgr.es/m/[email protected] Backpatch-through: 15 Branch ------ REL_16_STABLE Details ------- https://git.postgresql.org/pg/commitdiff/21a61b87f47b6a1b359021bf9f71b14bbf805330 Modified Files -------------- src/backend/executor/nodeModifyTable.c | 8 +- src/include/access/tableam.h | 15 ++- .../isolation/expected/merge-match-recheck.out | 136 +++++++++++++++++++++ src/test/isolation/specs/merge-match-recheck.spec | 18 +++ 4 files changed, 169 insertions(+), 8 deletions(-)
