From 107383513478e08da7f8989b19b172f618342940 Mon Sep 17 00:00:00 2001 From: Surya Poondla Date: Mon, 19 Oct 2026 11:53:07 -0700 Subject: [PATCH 2/2] Add isolation test for ATTACH PARTITION lock ordering ALTER TABLE ... ATTACH PARTITION on a table that is itself a partition must lock the target's ancestors before the target, because a recursing ALTER TABLE on the root locks the tree from the top down. Test that ATTACH waits for the root without holding any of its partitions, using LOCK TABLE ONLY to open the window between the recursing command's lock on the root and its locks on the partitions. A three-level hierarchy is used so that pre-locking only the target's direct parent would still fail. Discussion: https://postgr.es/m/CFACA0EB-7E6F-4FAA-9ACE-1FC2226D7482@gmail.com --- .../expected/partition-attach-lock-order.out | 9 +++++ src/test/isolation/isolation_schedule | 1 + .../specs/partition-attach-lock-order.spec | 39 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/test/isolation/expected/partition-attach-lock-order.out create mode 100644 src/test/isolation/specs/partition-attach-lock-order.spec diff --git a/src/test/isolation/expected/partition-attach-lock-order.out b/src/test/isolation/expected/partition-attach-lock-order.out new file mode 100644 index 00000000000..eab72c34713 --- /dev/null +++ b/src/test/isolation/expected/partition-attach-lock-order.out @@ -0,0 +1,9 @@ +Parsed test spec with 2 sessions + +starting permutation: s1begin s1lock s2attach s1alter s1commit +step s1begin: BEGIN; +step s1lock: LOCK TABLE ONLY attach_lock_root IN ACCESS EXCLUSIVE MODE; +step s2attach: ALTER TABLE attach_lock_mid2 ATTACH PARTITION attach_lock_new FOR VALUES FROM (0) TO (100); +step s1alter: ALTER TABLE attach_lock_root ALTER COLUMN id SET DEFAULT 0; +step s1commit: COMMIT; +step s2attach: <... completed> diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index bf9a2037c70..7c1af1c8ba7 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -113,6 +113,7 @@ test: predicate-hash test: predicate-gist test: predicate-gin test: partition-concurrent-attach +test: partition-attach-lock-order test: partition-drop-index-locking test: partition-key-update-1 test: partition-key-update-2 diff --git a/src/test/isolation/specs/partition-attach-lock-order.spec b/src/test/isolation/specs/partition-attach-lock-order.spec new file mode 100644 index 00000000000..cdd74b30ca3 --- /dev/null +++ b/src/test/isolation/specs/partition-attach-lock-order.spec @@ -0,0 +1,39 @@ +# Verify that ALTER TABLE ... ATTACH PARTITION locks all ancestors of the +# target table, from the root down, before locking the target itself. +# +# ATTACH PARTITION needs the partition constraint of its target, which +# generate_partition_qual() builds by walking up the partition tree and +# locking each ancestor. A recursing ALTER TABLE on the root locks the tree +# from the top down, so if ATTACH locked the target before its ancestors, +# the two could deadlock. Three levels are used so that locking only the +# target's direct parent first would not be enough. + +setup +{ + CREATE TABLE attach_lock_root (id int) PARTITION BY RANGE (id); + CREATE TABLE attach_lock_mid1 PARTITION OF attach_lock_root FOR VALUES FROM (0) TO (1000) PARTITION BY RANGE (id); + CREATE TABLE attach_lock_mid2 PARTITION OF attach_lock_mid1 FOR VALUES FROM (0) TO (500) PARTITION BY RANGE (id); + CREATE TABLE attach_lock_new (id int); +} + +teardown +{ + DROP TABLE attach_lock_new; + DROP TABLE attach_lock_root; +} + +# ALTER TABLE ... SET DEFAULT on the root locks the root and then recurses to +# its partitions. We can simulate ATTACH PARTITION starting between those +# steps by locking only the root beforehand. +session s1 +step s1begin { BEGIN; } +step s1lock { LOCK TABLE ONLY attach_lock_root IN ACCESS EXCLUSIVE MODE; } +step s1alter { ALTER TABLE attach_lock_root ALTER COLUMN id SET DEFAULT 0; } +step s1commit { COMMIT; } + +session s2 +step s2attach { ALTER TABLE attach_lock_mid2 ATTACH PARTITION attach_lock_new FOR VALUES FROM (0) TO (100); } + +# s2attach must wait for the root lock without holding a lock on any of the +# root's partitions, so that s1alter can complete. +permutation s1begin s1lock s2attach s1alter s1commit -- 2.39.5 (Apple Git-154)