mirror of https://github.com/postgres/postgres
This commit adds an isolation test showing that temporal foreign keys do not permit referential integrity violations under concurrency, like fk-snapshot-2. You can show that the test fails by passing false for detectNewRows to ri_PerformCheck in ri_restrict. Author: Paul Jungwirth <pj@illuminatedcomputing.com> Reviewed-by: Rustam ALLAKOV <rustamallakov@gmail.com> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com> Reviewed-by: Robert Haas <robertmhaas@gmail.com> Discussion: https://postgr.es/m/CA+renyUp=xja80rBaB6NpY3RRdi750y046x28bo_xg29zKY72Q@mail.gmail.commaster
parent
a2b4102a21
commit
e8cec3d179
@ -0,0 +1,213 @@ |
|||||||
|
Parsed test spec with 2 sessions |
||||||
|
|
||||||
|
starting permutation: s1rr s2rr s2ins s1del s2c s1c |
||||||
|
step s1rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1del: DELETE FROM parent WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1del: <... completed> |
||||||
|
ERROR: update or delete on table "parent" violates foreign key constraint "child_parent_id_valid_at_fkey" on table "child" |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rr s2rr s1del s2ins s1c s2c |
||||||
|
step s1rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s1del: DELETE FROM parent WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: could not serialize access due to concurrent update |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rc s2rc s2ins s1del s2c s1c |
||||||
|
step s1rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1del: DELETE FROM parent WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1del: <... completed> |
||||||
|
ERROR: update or delete on table "parent" violates foreign key constraint "child_parent_id_valid_at_fkey" on table "child" |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rc s2rc s1del s2ins s1c s2c |
||||||
|
step s1rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s1del: DELETE FROM parent WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: insert or update on table "child" violates foreign key constraint "child_parent_id_valid_at_fkey" |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1ser s2ser s2ins s1del s2c s1c |
||||||
|
step s1ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1del: DELETE FROM parent WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1del: <... completed> |
||||||
|
ERROR: update or delete on table "parent" violates foreign key constraint "child_parent_id_valid_at_fkey" on table "child" |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1ser s2ser s1del s2ins s1c s2c |
||||||
|
step s1ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s1del: DELETE FROM parent WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: could not serialize access due to concurrent update |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rc s2rc s2ins s1upok s2c s1c |
||||||
|
step s1rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1upok: UPDATE parent SET valid_at = '[2020-01-01,2026-01-01)' WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1upok: <... completed> |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rc s2rc s1upok s2ins s1c s2c |
||||||
|
step s1rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s1upok: UPDATE parent SET valid_at = '[2020-01-01,2026-01-01)' WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rr s2rr s2ins s1upok s2c s1c |
||||||
|
step s1rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1upok: UPDATE parent SET valid_at = '[2020-01-01,2026-01-01)' WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1upok: <... completed> |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rr s2rr s1upok s2ins s1c s2c |
||||||
|
step s1rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s1upok: UPDATE parent SET valid_at = '[2020-01-01,2026-01-01)' WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: could not serialize access due to concurrent update |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1ser s2ser s2ins s1upok s2c s1c |
||||||
|
step s1ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1upok: UPDATE parent SET valid_at = '[2020-01-01,2026-01-01)' WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1upok: <... completed> |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1ser s2ser s1upok s2ins s1c s2c |
||||||
|
step s1ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s1upok: UPDATE parent SET valid_at = '[2020-01-01,2026-01-01)' WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: could not serialize access due to concurrent update |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rc s2rc s2ins s1upbad s2c s1c |
||||||
|
step s1rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1upbad: UPDATE parent SET valid_at = '[2020-01-01,2024-01-01)' WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1upbad: <... completed> |
||||||
|
ERROR: update or delete on table "parent" violates foreign key constraint "child_parent_id_valid_at_fkey" on table "child" |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rc s2rc s1upbad s2ins s1c s2c |
||||||
|
step s1rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s2rc: BEGIN ISOLATION LEVEL READ COMMITTED; |
||||||
|
step s1upbad: UPDATE parent SET valid_at = '[2020-01-01,2024-01-01)' WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: insert or update on table "child" violates foreign key constraint "child_parent_id_valid_at_fkey" |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rr s2rr s2ins s1upbad s2c s1c |
||||||
|
step s1rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1upbad: UPDATE parent SET valid_at = '[2020-01-01,2024-01-01)' WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1upbad: <... completed> |
||||||
|
ERROR: update or delete on table "parent" violates foreign key constraint "child_parent_id_valid_at_fkey" on table "child" |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1rr s2rr s1upbad s2ins s1c s2c |
||||||
|
step s1rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s2rr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||||
|
step s1upbad: UPDATE parent SET valid_at = '[2020-01-01,2024-01-01)' WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: could not serialize access due to concurrent update |
||||||
|
step s2c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1ser s2ser s2ins s1upbad s2c s1c |
||||||
|
step s1ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
|
||||||
|
step s1upbad: UPDATE parent SET valid_at = '[2020-01-01,2024-01-01)' WHERE id = '[1,2)'; <waiting ...> |
||||||
|
step s2c: COMMIT; |
||||||
|
step s1upbad: <... completed> |
||||||
|
ERROR: update or delete on table "parent" violates foreign key constraint "child_parent_id_valid_at_fkey" on table "child" |
||||||
|
step s1c: COMMIT; |
||||||
|
|
||||||
|
starting permutation: s1ser s2ser s1upbad s2ins s1c s2c |
||||||
|
step s1ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s2ser: BEGIN ISOLATION LEVEL SERIALIZABLE; |
||||||
|
step s1upbad: UPDATE parent SET valid_at = '[2020-01-01,2024-01-01)' WHERE id = '[1,2)'; |
||||||
|
step s2ins: |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
<waiting ...> |
||||||
|
step s1c: COMMIT; |
||||||
|
step s2ins: <... completed> |
||||||
|
ERROR: could not serialize access due to concurrent update |
||||||
|
step s2c: COMMIT; |
@ -0,0 +1,82 @@ |
|||||||
|
# RI Trigger test |
||||||
|
# |
||||||
|
# Test C-based temporal referential integrity enforcement. |
||||||
|
# Under REPEATABLE READ we need some snapshot trickery in C, |
||||||
|
# or we would permit things that violate referential integrity. |
||||||
|
|
||||||
|
setup |
||||||
|
{ |
||||||
|
CREATE TABLE parent ( |
||||||
|
id int4range NOT NULL, |
||||||
|
valid_at daterange NOT NULL, |
||||||
|
PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)); |
||||||
|
CREATE TABLE child ( |
||||||
|
id int4range NOT NULL, |
||||||
|
valid_at daterange NOT NULL, |
||||||
|
parent_id int4range, |
||||||
|
FOREIGN KEY (parent_id, PERIOD valid_at) REFERENCES parent); |
||||||
|
INSERT INTO parent VALUES ('[1,2)', '[2020-01-01,2030-01-01)'); |
||||||
|
} |
||||||
|
|
||||||
|
teardown { DROP TABLE parent, child; } |
||||||
|
|
||||||
|
session s1 |
||||||
|
step s1rc { BEGIN ISOLATION LEVEL READ COMMITTED; } |
||||||
|
step s1rr { BEGIN ISOLATION LEVEL REPEATABLE READ; } |
||||||
|
step s1ser { BEGIN ISOLATION LEVEL SERIALIZABLE; } |
||||||
|
step s1del { DELETE FROM parent WHERE id = '[1,2)'; } |
||||||
|
step s1upok { UPDATE parent SET valid_at = '[2020-01-01,2026-01-01)' WHERE id = '[1,2)'; } |
||||||
|
step s1upbad { UPDATE parent SET valid_at = '[2020-01-01,2024-01-01)' WHERE id = '[1,2)'; } |
||||||
|
step s1c { COMMIT; } |
||||||
|
|
||||||
|
session s2 |
||||||
|
step s2rc { BEGIN ISOLATION LEVEL READ COMMITTED; } |
||||||
|
step s2rr { BEGIN ISOLATION LEVEL REPEATABLE READ; } |
||||||
|
step s2ser { BEGIN ISOLATION LEVEL SERIALIZABLE; } |
||||||
|
step s2ins { |
||||||
|
INSERT INTO child VALUES ('[1,2)', '[2020-01-01,2025-01-01)', '[1,2)'); |
||||||
|
} |
||||||
|
step s2c { COMMIT; } |
||||||
|
|
||||||
|
# Violates referential integrity unless we use an up-to-date crosscheck snapshot: |
||||||
|
permutation s1rr s2rr s2ins s1del s2c s1c |
||||||
|
|
||||||
|
# Raises a can't-serialize exception |
||||||
|
# when the INSERT trigger does SELECT FOR KEY SHARE: |
||||||
|
permutation s1rr s2rr s1del s2ins s1c s2c |
||||||
|
|
||||||
|
# Test the same scenarios in READ COMMITTED: |
||||||
|
# A crosscheck snapshot is not required here. |
||||||
|
permutation s1rc s2rc s2ins s1del s2c s1c |
||||||
|
permutation s1rc s2rc s1del s2ins s1c s2c |
||||||
|
|
||||||
|
# Test the same scenarios in SERIALIZABLE: |
||||||
|
# We should report the FK violation: |
||||||
|
permutation s1ser s2ser s2ins s1del s2c s1c |
||||||
|
# We raise a concurrent update error |
||||||
|
# which is good enough: |
||||||
|
permutation s1ser s2ser s1del s2ins s1c s2c |
||||||
|
|
||||||
|
# Also check updating the valid time (without violating RI): |
||||||
|
|
||||||
|
# ...with READ COMMITED: |
||||||
|
permutation s1rc s2rc s2ins s1upok s2c s1c |
||||||
|
permutation s1rc s2rc s1upok s2ins s1c s2c |
||||||
|
# ...with REPEATABLE READ: |
||||||
|
permutation s1rr s2rr s2ins s1upok s2c s1c |
||||||
|
permutation s1rr s2rr s1upok s2ins s1c s2c |
||||||
|
# ...with SERIALIZABLE: |
||||||
|
permutation s1ser s2ser s2ins s1upok s2c s1c |
||||||
|
permutation s1ser s2ser s1upok s2ins s1c s2c |
||||||
|
|
||||||
|
# Also check updating the valid time (while violating RI): |
||||||
|
|
||||||
|
# ...with READ COMMITED: |
||||||
|
permutation s1rc s2rc s2ins s1upbad s2c s1c |
||||||
|
permutation s1rc s2rc s1upbad s2ins s1c s2c |
||||||
|
# ...with REPEATABLE READ: |
||||||
|
permutation s1rr s2rr s2ins s1upbad s2c s1c |
||||||
|
permutation s1rr s2rr s1upbad s2ins s1c s2c |
||||||
|
# ...with SERIALIZABLE: |
||||||
|
permutation s1ser s2ser s2ins s1upbad s2c s1c |
||||||
|
permutation s1ser s2ser s1upbad s2ins s1c s2c |
Loading…
Reference in new issue