From 6e6668b04bc4e47df4e6e7ea8154e5abd28a209b Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Tue, 27 Oct 2026 21:32:59 -0400 Subject: [PATCH 2/3] Add an isolation test for not-null constraints seen by older snapshots. --- .../expected/notnull-old-snapshot.out | 85 +++++++++++++++++++ src/test/isolation/isolation_schedule | 1 + .../isolation/specs/notnull-old-snapshot.spec | 34 ++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/test/isolation/expected/notnull-old-snapshot.out create mode 100644 src/test/isolation/specs/notnull-old-snapshot.spec diff --git a/src/test/isolation/expected/notnull-old-snapshot.out b/src/test/isolation/expected/notnull-old-snapshot.out new file mode 100644 index 00000000000..4c766cd710e --- /dev/null +++ b/src/test/isolation/expected/notnull-old-snapshot.out @@ -0,0 +1,85 @@ +Parsed test spec with 2 sessions + +starting permutation: s1_begin s2_validate s1_isnull s1_counta s1_cols s1_coalesce s1_commit +step s1_begin: BEGIN ISOLATION LEVEL REPEATABLE READ; SELECT count(*) FROM nn_snap WHERE a IS NULL; +count +----- + 5 +(1 row) + +step s2_validate: UPDATE nn_snap SET a = 0 WHERE a IS NULL; ALTER TABLE nn_snap VALIDATE CONSTRAINT nn_snap_a_nn; +step s1_isnull: SELECT count(*) FROM nn_snap WHERE a IS NULL; +count +----- + 5 +(1 row) + +step s1_counta: SELECT count(a), count(*) FROM nn_snap; +count|count +-----+----- + 5| 10 +(1 row) + +step s1_cols: SELECT id, a, b FROM nn_snap WHERE id <= 5; +id|a| b +--+-+--- + 1| |101 + 2| |102 + 3| |103 + 4| |104 + 5| |105 +(5 rows) + +step s1_coalesce: SELECT id, coalesce(a, -1) FROM nn_snap WHERE id <= 5; +id|coalesce +--+-------- + 1| -1 + 2| -1 + 3| -1 + 4| -1 + 5| -1 +(5 rows) + +step s1_commit: COMMIT; + +starting permutation: s1_snap s2_setnotnull s1_isnull s1_counta s1_cols s1_coalesce s1_commit +step s1_snap: BEGIN ISOLATION LEVEL REPEATABLE READ; SELECT 1; +?column? +-------- + 1 +(1 row) + +step s2_setnotnull: ALTER TABLE nn_snap DROP CONSTRAINT nn_snap_a_nn; UPDATE nn_snap SET a = 0 WHERE a IS NULL; ALTER TABLE nn_snap ALTER a SET NOT NULL; +step s1_isnull: SELECT count(*) FROM nn_snap WHERE a IS NULL; +count +----- + 5 +(1 row) + +step s1_counta: SELECT count(a), count(*) FROM nn_snap; +count|count +-----+----- + 5| 10 +(1 row) + +step s1_cols: SELECT id, a, b FROM nn_snap WHERE id <= 5; +id|a| b +--+-+--- + 1| |101 + 2| |102 + 3| |103 + 4| |104 + 5| |105 +(5 rows) + +step s1_coalesce: SELECT id, coalesce(a, -1) FROM nn_snap WHERE id <= 5; +id|coalesce +--+-------- + 1| -1 + 2| -1 + 3| -1 + 4| -1 + 5| -1 +(5 rows) + +step s1_commit: COMMIT; diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index bf9a2037c70..074d0183802 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -99,6 +99,7 @@ test: alter-table-1 test: alter-table-2 test: alter-table-3 test: alter-table-4 +test: notnull-old-snapshot test: create-trigger test: sequence-ddl test: async-notify diff --git a/src/test/isolation/specs/notnull-old-snapshot.spec b/src/test/isolation/specs/notnull-old-snapshot.spec new file mode 100644 index 00000000000..09c311ed113 --- /dev/null +++ b/src/test/isolation/specs/notnull-old-snapshot.spec @@ -0,0 +1,34 @@ +# A snapshot older than a not-null constraint can still see tuples with +# nulls in the constrained column. Neither the planner nor the tuple +# deforming fast path may rely on the constraint for such a snapshot. + +setup +{ + CREATE TABLE nn_snap (id int PRIMARY KEY, a int, b int, c text); + INSERT INTO nn_snap SELECT g, CASE WHEN g <= 5 THEN NULL ELSE g * 10 END, + g + 100, 'c' || g FROM generate_series(1, 10) g; + ALTER TABLE nn_snap ADD CONSTRAINT nn_snap_a_nn NOT NULL a NOT VALID; +} + +teardown +{ + DROP TABLE nn_snap; +} + +session s1 +step s1_begin { BEGIN ISOLATION LEVEL REPEATABLE READ; SELECT count(*) FROM nn_snap WHERE a IS NULL; } +step s1_snap { BEGIN ISOLATION LEVEL REPEATABLE READ; SELECT 1; } +step s1_isnull { SELECT count(*) FROM nn_snap WHERE a IS NULL; } +step s1_counta { SELECT count(a), count(*) FROM nn_snap; } +step s1_cols { SELECT id, a, b FROM nn_snap WHERE id <= 5; } +step s1_coalesce { SELECT id, coalesce(a, -1) FROM nn_snap WHERE id <= 5; } +step s1_commit { COMMIT; } + +session s2 +step s2_validate { UPDATE nn_snap SET a = 0 WHERE a IS NULL; ALTER TABLE nn_snap VALIDATE CONSTRAINT nn_snap_a_nn; } +step s2_setnotnull { ALTER TABLE nn_snap DROP CONSTRAINT nn_snap_a_nn; UPDATE nn_snap SET a = 0 WHERE a IS NULL; ALTER TABLE nn_snap ALTER a SET NOT NULL; } + +# constraint validated after s1 took its snapshot and read the table +permutation s1_begin s2_validate s1_isnull s1_counta s1_cols s1_coalesce s1_commit +# constraint created after s1 took its snapshot +permutation s1_snap s2_setnotnull s1_isnull s1_counta s1_cols s1_coalesce s1_commit -- 2.37.1 (Apple Git-137.1)