From 9409297e6c5a2d05183e2a87d7e3e41de2b19fa5 Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Tue, 28 Apr 2026 14:55:15 +0900 Subject: [PATCH v2] Use "concurrent delete" in serialization error for TM_Deleted cases In ExecLockRows() and ri_LockPKTuple(), the TM_Deleted code path was using the same "could not serialize access due to concurrent update" message as the TM_Updated path. Use "concurrent delete" instead, since the tuple was deleted, not updated. The ExecLockRows() instance was likely a copy-paste error per Andres; the ri_LockPKTuple() instance was carried over from the same pattern in commit 2da86c1ef9. Update affected isolation test expected files accordingly and add a new test to fk-concurrent-pk-upd.spec with concurrent delete of the PK row. The ExecLockRows() change is master-only for lack of user complaints and to avoid breaking anything that might match on the error text. Reported-by: jian he Author: Amit Langote Reviewed-by: Junwang Zhao Discussion: https://postgr.es/m/CACJufxEG1JTCq4A1gnNAu-bGAq9Xn=Xkf7kC3TRWFz6iuUOuRA@mail.gmail.com --- src/backend/executor/nodeLockRows.c | 2 +- src/backend/utils/adt/ri_triggers.c | 2 +- .../expected/fk-concurrent-pk-upd.out | 20 +++++++++++++++++++ .../isolation/expected/fk-partitioned-2.out | 4 ++-- src/test/isolation/expected/fk-snapshot-2.out | 4 ++-- src/test/isolation/expected/fk-snapshot-3.out | 4 ++-- .../isolation/specs/fk-concurrent-pk-upd.spec | 3 +++ 7 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 8d865470780..3bee818a8b4 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -234,7 +234,7 @@ lnext: if (IsolationUsesXactSnapshot()) ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), - errmsg("could not serialize access due to concurrent update"))); + errmsg("could not serialize access due to concurrent delete"))); /* tuple was deleted so don't return it */ goto lnext; diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index f63a7f0b580..dc89c686394 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -3244,7 +3244,7 @@ ri_LockPKTuple(Relation pk_rel, TupleTableSlot *slot, Snapshot snap, if (IsolationUsesXactSnapshot()) ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), - errmsg("could not serialize access due to concurrent update"))); + errmsg("could not serialize access due to concurrent delete"))); return false; case TM_Updated: diff --git a/src/test/isolation/expected/fk-concurrent-pk-upd.out b/src/test/isolation/expected/fk-concurrent-pk-upd.out index 4dd9535d3c0..84937399249 100644 --- a/src/test/isolation/expected/fk-concurrent-pk-upd.out +++ b/src/test/isolation/expected/fk-concurrent-pk-upd.out @@ -84,6 +84,26 @@ child_key|parent_key (0 rows) +starting permutation: s2b s2dkey s3b s3i s2c s3c s2s s3s +step s2b: BEGIN; +step s2dkey: DELETE FROM parent WHERE parent_key = 1; +step s3b: BEGIN ISOLATION LEVEL REPEATABLE READ; +step s3i: INSERT INTO child VALUES (2, 1); +step s2c: COMMIT; +step s3i: <... completed> +ERROR: could not serialize access due to concurrent delete +step s3c: COMMIT; +step s2s: SELECT * FROM parent; +parent_key|aux +----------+--- +(0 rows) + +step s3s: SELECT * FROM child; +child_key|parent_key +---------+---------- +(0 rows) + + starting permutation: s2b s2uaux s3b s3i s2c s3c s2s s3s step s2b: BEGIN; step s2uaux: UPDATE parent SET aux = 'bar' WHERE parent_key = 1; diff --git a/src/test/isolation/expected/fk-partitioned-2.out b/src/test/isolation/expected/fk-partitioned-2.out index db621bee2d6..fd3d97c832f 100644 --- a/src/test/isolation/expected/fk-partitioned-2.out +++ b/src/test/isolation/expected/fk-partitioned-2.out @@ -22,7 +22,7 @@ step s2bs: begin isolation level serializable; select 1; step s2i: insert into pfk values (1); step s1c: commit; step s2i: <... completed> -ERROR: could not serialize access due to concurrent update +ERROR: could not serialize access due to concurrent delete step s2c: commit; starting permutation: s1b s2b s1d s2i s1c s2c @@ -47,7 +47,7 @@ step s1d: delete from ppk where a = 1; step s2i: insert into pfk values (1); step s1c: commit; step s2i: <... completed> -ERROR: could not serialize access due to concurrent update +ERROR: could not serialize access due to concurrent delete step s2c: commit; starting permutation: s1b s2b s2i s1d s2c s1c diff --git a/src/test/isolation/expected/fk-snapshot-2.out b/src/test/isolation/expected/fk-snapshot-2.out index 0a4c9646fca..7333643e9ac 100644 --- a/src/test/isolation/expected/fk-snapshot-2.out +++ b/src/test/isolation/expected/fk-snapshot-2.out @@ -17,7 +17,7 @@ step s1del: DELETE FROM parent WHERE parent_id = 1; step s2ins: INSERT INTO child VALUES (1, 1); step s1c: COMMIT; step s2ins: <... completed> -ERROR: could not serialize access due to concurrent update +ERROR: could not serialize access due to concurrent delete step s2c: COMMIT; starting permutation: s1rc s2rc s2ins s1del s2c s1c @@ -57,5 +57,5 @@ step s1del: DELETE FROM parent WHERE parent_id = 1; step s2ins: INSERT INTO child VALUES (1, 1); step s1c: COMMIT; step s2ins: <... completed> -ERROR: could not serialize access due to concurrent update +ERROR: could not serialize access due to concurrent delete step s2c: COMMIT; diff --git a/src/test/isolation/expected/fk-snapshot-3.out b/src/test/isolation/expected/fk-snapshot-3.out index f98cb72fdac..2dc490be48b 100644 --- a/src/test/isolation/expected/fk-snapshot-3.out +++ b/src/test/isolation/expected/fk-snapshot-3.out @@ -21,7 +21,7 @@ step s2ins: step s1c: COMMIT; step s2ins: <... completed> -ERROR: could not serialize access due to concurrent update +ERROR: could not serialize access due to concurrent delete step s2c: COMMIT; starting permutation: s1rc s2rc s2ins s1del s2c s1c @@ -69,7 +69,7 @@ step s2ins: step s1c: COMMIT; step s2ins: <... completed> -ERROR: could not serialize access due to concurrent update +ERROR: could not serialize access due to concurrent delete step s2c: COMMIT; starting permutation: s1rc s2rc s2ins s1upok s2c s1c diff --git a/src/test/isolation/specs/fk-concurrent-pk-upd.spec b/src/test/isolation/specs/fk-concurrent-pk-upd.spec index 03dc7f260cd..139c2b4d8c7 100644 --- a/src/test/isolation/specs/fk-concurrent-pk-upd.spec +++ b/src/test/isolation/specs/fk-concurrent-pk-upd.spec @@ -31,6 +31,7 @@ step s2b { BEGIN; } step s2ukey { UPDATE parent SET parent_key = 2 WHERE parent_key = 1; } step s2uaux { UPDATE parent SET aux = 'bar' WHERE parent_key = 1; } step s2ukey2 { UPDATE parent SET parent_key = 1 WHERE parent_key = 2; } +step s2dkey { DELETE FROM parent WHERE parent_key = 1; } step s2c { COMMIT; } step s2s { SELECT * FROM parent; } @@ -49,5 +50,7 @@ permutation s2b s2ukey s1b s1i s2ukey2 s2c s1c s2s s1s # RR: key update -> serialization failure permutation s2b s2ukey s3b s3i s2c s3c s2s s3s +# RR: key delete -> serialization failure +permutation s2b s2dkey s3b s3i s2c s3c s2s s3s # RR: non-key update -> old version visible via transaction snapshot permutation s2b s2uaux s3b s3i s2c s3c s2s s3s -- 2.47.3