From 30af36c9564b0b1a56c3a3a5809c5c26eb18da08 Mon Sep 17 00:00:00 2001 From: Utkarash Singh Date: Tue, 9 Jun 2026 16:22:58 +0530 Subject: [PATCH] test(nix): pin MERGE serialization fix with an isolation spec MERGE must raise serialization failure (40001) under REPEATABLE READ when its target row was updated+committed concurrently (upstream fix, PG 15.16/17.8). The expected output reflects the fixed behaviour, so this spec fails on pre-fix 15.14/17.6 and passes on 15.18/17.10. Ref: PSQL-1277 --- nix/checks.nix | 5 ++- .../expected/merge_serialization.out | 16 ++++++++++ .../isolation/specs/merge_serialization.spec | 32 +++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 nix/tests/isolation/expected/merge_serialization.out create mode 100644 nix/tests/isolation/specs/merge_serialization.spec diff --git a/nix/checks.nix b/nix/checks.nix index b328ccb2c..b2747cf5b 100644 --- a/nix/checks.nix +++ b/nix/checks.nix @@ -277,7 +277,10 @@ # Concurrency/isolation specs run via pg_isolation_regress (the stock # PostgreSQL isolation tester). Specs live in tests/isolation/specs/, # expected output in tests/isolation/expected/. Add new spec names here. - isolationSpecList = [ "sample_isolation" ]; + isolationSpecList = [ + "merge_serialization" + "sample_isolation" + ]; in pkgs.writeShellApplication rec { name = "postgres-${pgpkg.version}-check-harness"; diff --git a/nix/tests/isolation/expected/merge_serialization.out b/nix/tests/isolation/expected/merge_serialization.out new file mode 100644 index 000000000..13421ae42 --- /dev/null +++ b/nix/tests/isolation/expected/merge_serialization.out @@ -0,0 +1,16 @@ +Parsed test spec with 2 sessions + +starting permutation: s1_begin s1_snapshot s2_update s1_merge s1_commit +step s1_begin: BEGIN ISOLATION LEVEL REPEATABLE READ; +step s1_snapshot: SELECT v FROM merge_target WHERE k = 1; +v +- +0 +(1 row) + +step s2_update: UPDATE merge_target SET v = v + 100 WHERE k = 1; +step s1_merge: MERGE INTO merge_target t + USING (SELECT 1 AS k) s ON t.k = s.k + WHEN MATCHED THEN UPDATE SET v = t.v + 1; +ERROR: could not serialize access due to concurrent update +step s1_commit: COMMIT; diff --git a/nix/tests/isolation/specs/merge_serialization.spec b/nix/tests/isolation/specs/merge_serialization.spec new file mode 100644 index 000000000..e02b3621a --- /dev/null +++ b/nix/tests/isolation/specs/merge_serialization.spec @@ -0,0 +1,32 @@ +# Pins the upstream fix (PG 15.16 / 17.8) where MERGE must raise a +# serialization failure (SQLSTATE 40001) under REPEATABLE READ when its target +# row was updated and committed by a concurrent transaction after the MERGE +# transaction took its snapshot. Before the fix this concurrent-update check +# was silently skipped for MERGE (unlike a plain UPDATE). +# +# s1 opens a REPEATABLE READ transaction and takes its snapshot (s1_snapshot); +# s2 then updates+commits the row; s1's MERGE on that row must fail with 40001. + +setup +{ + CREATE TABLE merge_target (k int PRIMARY KEY, v int); + INSERT INTO merge_target VALUES (1, 0); +} + +teardown +{ + DROP TABLE merge_target; +} + +session s1 +step s1_begin { BEGIN ISOLATION LEVEL REPEATABLE READ; } +step s1_snapshot { SELECT v FROM merge_target WHERE k = 1; } +step s1_merge { MERGE INTO merge_target t + USING (SELECT 1 AS k) s ON t.k = s.k + WHEN MATCHED THEN UPDATE SET v = t.v + 1; } +step s1_commit { COMMIT; } + +session s2 +step s2_update { UPDATE merge_target SET v = v + 100 WHERE k = 1; } + +permutation s1_begin s1_snapshot s2_update s1_merge s1_commit