Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion nix/checks.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
16 changes: 16 additions & 0 deletions nix/tests/isolation/expected/merge_serialization.out
Original file line number Diff line number Diff line change
@@ -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;
32 changes: 32 additions & 0 deletions nix/tests/isolation/specs/merge_serialization.spec
Original file line number Diff line number Diff line change
@@ -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
Loading