mirror of https://github.com/postgres/postgres
Allow a partition be detached from its partitioned table without blocking concurrent queries, by running in two transactions and only requiring ShareUpdateExclusive in the partitioned table. Because it runs in two transactions, it cannot be used in a transaction block. This is the main reason to use dedicated syntax: so that users can choose to use the original mode if they need it. But also, it doesn't work when a default partition exists (because an exclusive lock would still need to be obtained on it, in order to change its partition constraint.) In case the second transaction is cancelled or a crash occurs, there's ALTER TABLE .. DETACH PARTITION .. FINALIZE, which executes the final steps. The main trick to make this work is the addition of column pg_inherits.inhdetachpending, initially false; can only be set true in the first part of this command. Once that is committed, concurrent transactions that use a PartitionDirectory will include or ignore partitions so marked: in optimizer they are ignored if the row is marked committed for the snapshot; in executor they are always included. As a result, and because of the way PartitionDirectory caches partition descriptors, queries that were planned before the detach will see the rows in the detached partition and queries that are planned after the detach, won't. A CHECK constraint is created that duplicates the partition constraint. This is probably not strictly necessary, and some users will prefer to remove it afterwards, but if the partition is re-attached to a partitioned table, the constraint needn't be rechecked. Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Amit Langote <amitlangote09@gmail.com> Reviewed-by: Justin Pryzby <pryzby@telsasoft.com> Discussion: https://postgr.es/m/20200803234854.GA24158@alvherre.pgsqlpull/64/head
parent
650d623530
commit
71f4c8c6f7
@ -0,0 +1,234 @@ |
||||
Parsed test spec with 3 sessions |
||||
|
||||
starting permutation: s1b s1s s2detach s1s s1c s1s |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
|
||||
starting permutation: s1b s1s s2detach s1s s3s s3i s1c s3i s2drop s1s |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
step s3s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
step s3i: SELECT relpartbound IS NULL FROM pg_class where relname = 'd_listp2'; |
||||
?column? |
||||
|
||||
f |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
step s3i: SELECT relpartbound IS NULL FROM pg_class where relname = 'd_listp2'; |
||||
?column? |
||||
|
||||
t |
||||
step s2drop: DROP TABLE d_listp2; |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
|
||||
starting permutation: s1b s1s s2detach s1ins s1s s1c |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1ins: INSERT INTO d_listp VALUES (1); |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
1 |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s1b s1s s1ins2 s2detach s1ins s1s s1c |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1ins2: INSERT INTO d_listp VALUES (2); |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1ins: INSERT INTO d_listp VALUES (1); |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
1 |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s1brr s1s s2detach s1ins s1s s1c |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1ins: INSERT INTO d_listp VALUES (1); |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
1 |
||||
2 |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s1brr s1s s2detach s1s s1c |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s1b s1ins2 s2detach s3ins2 s1c |
||||
step s1b: BEGIN; |
||||
step s1ins2: INSERT INTO d_listp VALUES (2); |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s3ins2: INSERT INTO d_listp VALUES (2); |
||||
ERROR: no partition of relation "d_listp" found for row |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s1brr s1prep s1s s2detach s1s s1exec1 s3s s1dealloc s1c |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prep: PREPARE f(int) AS INSERT INTO d_listp VALUES ($1); |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1exec1: EXECUTE f(1); |
||||
step s3s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
step s1dealloc: DEALLOCATE f; |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s1brr s1prep s1exec2 s2detach s1s s1exec2 s3s s1c s1dealloc |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prep: PREPARE f(int) AS INSERT INTO d_listp VALUES ($1); |
||||
step s1exec2: EXECUTE f(2); |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
2 |
||||
step s1exec2: EXECUTE f(2); |
||||
step s3s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
step s1dealloc: DEALLOCATE f; |
||||
|
||||
starting permutation: s1brr s1prep s1s s2detach s1s s1exec2 s1c s1dealloc |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prep: PREPARE f(int) AS INSERT INTO d_listp VALUES ($1); |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1exec2: EXECUTE f(2); |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
step s1dealloc: DEALLOCATE f; |
||||
|
||||
starting permutation: s1brr s1prep s2detach s1s s1exec2 s1c s1dealloc |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prep: PREPARE f(int) AS INSERT INTO d_listp VALUES ($1); |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1exec2: EXECUTE f(2); |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
step s1dealloc: DEALLOCATE f; |
||||
|
||||
starting permutation: s1brr s1prep1 s2detach s1s s1exec2 s1c s1dealloc |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prep1: PREPARE f(int) AS INSERT INTO d_listp VALUES (1); |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1exec2: EXECUTE f(2); |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
step s1dealloc: DEALLOCATE f; |
||||
|
||||
starting permutation: s1brr s1prep2 s2detach s1s s1exec2 s1c s1dealloc |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prep2: PREPARE f(int) AS INSERT INTO d_listp VALUES (2); |
||||
step s2detach: ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; <waiting ...> |
||||
step s1s: SELECT * FROM d_listp; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1exec2: EXECUTE f(2); |
||||
step s1c: COMMIT; |
||||
step s2detach: <... completed> |
||||
step s1dealloc: DEALLOCATE f; |
@ -0,0 +1,66 @@ |
||||
Parsed test spec with 3 sessions |
||||
|
||||
starting permutation: s1b s1s s2d s3i1 s1c |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_lp_fk; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2d: ALTER TABLE d_lp_fk DETACH PARTITION d_lp_fk_1 CONCURRENTLY; <waiting ...> |
||||
step s3i1: INSERT INTO d_lp_fk_r VALUES (1); |
||||
ERROR: insert or update on table "d_lp_fk_r" violates foreign key constraint "d_lp_fk_r_a_fkey" |
||||
step s1c: COMMIT; |
||||
step s2d: <... completed> |
||||
|
||||
starting permutation: s1b s1s s2d s3i2 s3i2 s1c |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_lp_fk; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2d: ALTER TABLE d_lp_fk DETACH PARTITION d_lp_fk_1 CONCURRENTLY; <waiting ...> |
||||
step s3i2: INSERT INTO d_lp_fk_r VALUES (2); |
||||
step s3i2: INSERT INTO d_lp_fk_r VALUES (2); |
||||
step s1c: COMMIT; |
||||
step s2d: <... completed> |
||||
|
||||
starting permutation: s1b s1s s3i1 s2d s1c |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_lp_fk; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s3i1: INSERT INTO d_lp_fk_r VALUES (1); |
||||
step s2d: ALTER TABLE d_lp_fk DETACH PARTITION d_lp_fk_1 CONCURRENTLY; |
||||
ERROR: removing partition "d_lp_fk_1" violates foreign key constraint "d_lp_fk_r_a_fkey1" |
||||
step s1c: COMMIT; |
||||
|
||||
starting permutation: s1b s1s s3i2 s2d s1c |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_lp_fk; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s3i2: INSERT INTO d_lp_fk_r VALUES (2); |
||||
step s2d: ALTER TABLE d_lp_fk DETACH PARTITION d_lp_fk_1 CONCURRENTLY; <waiting ...> |
||||
step s1c: COMMIT; |
||||
step s2d: <... completed> |
||||
|
||||
starting permutation: s1b s1s s3b s2d s3i1 s1c s3c |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d_lp_fk; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s3b: BEGIN; |
||||
step s2d: ALTER TABLE d_lp_fk DETACH PARTITION d_lp_fk_1 CONCURRENTLY; <waiting ...> |
||||
step s3i1: INSERT INTO d_lp_fk_r VALUES (1); |
||||
ERROR: insert or update on table "d_lp_fk_r" violates foreign key constraint "d_lp_fk_r_a_fkey" |
||||
step s1c: COMMIT; |
||||
step s2d: <... completed> |
||||
step s3c: COMMIT; |
@ -0,0 +1,282 @@ |
||||
Parsed test spec with 2 sessions |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s1describe s1alter |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s1describe: SELECT 'd3_listp' AS root, * FROM pg_partition_tree('d3_listp') |
||||
UNION ALL SELECT 'd3_listp1', * FROM pg_partition_tree('d3_listp1'); |
||||
root relid parentrelid isleaf level |
||||
|
||||
d3_listp d3_listp f 0 |
||||
d3_listp1 d3_listp1 t 0 |
||||
step s1alter: ALTER TABLE d3_listp1 ALTER a DROP NOT NULL; |
||||
ERROR: cannot alter partition "d3_listp1" with an incomplete detach |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1insert s1c |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1insert: INSERT INTO d3_listp VALUES (1); |
||||
ERROR: no partition of relation "d3_listp" found for row |
||||
step s1c: COMMIT; |
||||
|
||||
starting permutation: s2snitch s1brr s1s s2detach s1cancel s1insert s1c s1spart |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1insert: INSERT INTO d3_listp VALUES (1); |
||||
step s1c: COMMIT; |
||||
step s1spart: SELECT * FROM d3_listp1; |
||||
a |
||||
|
||||
1 |
||||
1 |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s1insertpart |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s1insertpart: INSERT INTO d3_listp1 VALUES (1); |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s1drop s1list |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s1drop: DROP TABLE d3_listp; |
||||
step s1list: SELECT relname FROM pg_catalog.pg_class |
||||
WHERE relname LIKE 'd3_listp%' ORDER BY 1; |
||||
relname |
||||
|
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s1trunc s1spart |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s1trunc: TRUNCATE TABLE d3_listp; |
||||
step s1spart: SELECT * FROM d3_listp1; |
||||
a |
||||
|
||||
1 |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s2begin s2drop s1s s2commit |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s2begin: BEGIN; |
||||
step s2drop: DROP TABLE d3_listp1; |
||||
step s1s: SELECT * FROM d3_listp; <waiting ...> |
||||
step s2commit: COMMIT; |
||||
step s1s: <... completed> |
||||
a |
||||
|
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s1b s1spart s2detachfinal s1c |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s1b: BEGIN; |
||||
step s1spart: SELECT * FROM d3_listp1; |
||||
a |
||||
|
||||
1 |
||||
step s2detachfinal: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 FINALIZE; <waiting ...> |
||||
step s1c: COMMIT; |
||||
step s2detachfinal: <... completed> |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s1b s1s s2detachfinal s1c |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
step s2detachfinal: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 FINALIZE; |
||||
step s1c: COMMIT; |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s1b s1spart s2detachfinal s1c |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s1b: BEGIN; |
||||
step s1spart: SELECT * FROM d3_listp1; |
||||
a |
||||
|
||||
1 |
||||
step s2detachfinal: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 FINALIZE; <waiting ...> |
||||
step s1c: COMMIT; |
||||
step s2detachfinal: <... completed> |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s2begin s2detachfinal s2commit |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s2begin: BEGIN; |
||||
step s2detachfinal: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 FINALIZE; |
||||
step s2commit: COMMIT; |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s2begin s2detachfinal s1spart s2commit |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s2begin: BEGIN; |
||||
step s2detachfinal: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 FINALIZE; |
||||
step s1spart: SELECT * FROM d3_listp1; <waiting ...> |
||||
step s2commit: COMMIT; |
||||
step s1spart: <... completed> |
||||
a |
||||
|
||||
1 |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1c s2begin s2detachfinal s1insertpart s2commit |
||||
step s2snitch: INSERT INTO d3_pid SELECT pg_backend_pid(); |
||||
step s1b: BEGIN; |
||||
step s1s: SELECT * FROM d3_listp; |
||||
a |
||||
|
||||
1 |
||||
step s2detach: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; <waiting ...> |
||||
step s1cancel: SELECT pg_cancel_backend(pid) FROM d3_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: COMMIT; |
||||
step s2begin: BEGIN; |
||||
step s2detachfinal: ALTER TABLE d3_listp DETACH PARTITION d3_listp1 FINALIZE; |
||||
step s1insertpart: INSERT INTO d3_listp1 VALUES (1); <waiting ...> |
||||
step s2commit: COMMIT; |
||||
step s1insertpart: <... completed> |
||||
unused step name: s1droppart |
@ -0,0 +1,351 @@ |
||||
Parsed test spec with 3 sessions |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1insert: insert into d4_fk values (1); |
||||
step s2detach: <... completed> |
||||
error in steps s1insert s2detach: ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1brr s1s s2detach s1cancel s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1brr: begin isolation level repeatable read; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1brr s1s s2detach s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1brr: begin isolation level repeatable read; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1insert: insert into d4_fk values (1); |
||||
step s2detach: <... completed> |
||||
error in steps s1insert s2detach: ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s1declare s2detach s1cancel s1fetchall s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s1declare s2detach s1fetchall s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1insert: insert into d4_fk values (1); |
||||
step s2detach: <... completed> |
||||
error in steps s1insert s2detach: ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s1declare s2detach s1cancel s1svpt s1insert s1rollback s1fetchall s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1svpt: savepoint f; |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1rollback: rollback to f; |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s1declare s2detach s1svpt s1insert s1rollback s1fetchall s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1svpt: savepoint f; |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1rollback: rollback to f; |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1c: commit; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s2snitch s1b s2detach s1declare s1cancel s1fetchall s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
2 |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s2detach s1declare s1fetchall s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
2 |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s2detach s1declare s1cancel s1svpt s1insert s1rollback s1fetchall s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s1svpt: savepoint f; |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1rollback: rollback to f; |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
2 |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s2detach s1declare s1svpt s1insert s1rollback s1fetchall s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; |
||||
step s1declare: declare f cursor for select * from d4_primary; |
||||
step s1svpt: savepoint f; |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1rollback: rollback to f; |
||||
step s1fetchall: fetch all from f; |
||||
a |
||||
|
||||
2 |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1brr s1declare2 s1fetchone s2detach s1cancel s1updcur s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1brr: begin isolation level repeatable read; |
||||
step s1declare2: declare f cursor for select * from d4_fk where a = 2; |
||||
step s1fetchone: fetch 1 from f; |
||||
a |
||||
|
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1updcur: update d4_fk set a = 1 where current of f; |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1brr s1declare2 s1fetchone s2detach s1updcur s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1brr: begin isolation level repeatable read; |
||||
step s1declare2: declare f cursor for select * from d4_fk where a = 2; |
||||
step s1fetchone: fetch 1 from f; |
||||
a |
||||
|
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1updcur: update d4_fk set a = 1 where current of f; |
||||
step s2detach: <... completed> |
||||
error in steps s1updcur s2detach: ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1brr s1declare2 s1fetchone s1updcur s2detach s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1brr: begin isolation level repeatable read; |
||||
step s1declare2: declare f cursor for select * from d4_fk where a = 2; |
||||
step s1fetchone: fetch 1 from f; |
||||
a |
||||
|
||||
2 |
||||
step s1updcur: update d4_fk set a = 1 where current of f; |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1c: commit; |
||||
step s2detach: <... completed> |
||||
error in steps s1c s2detach: ERROR: removing partition "d4_primary1" violates foreign key constraint "d4_fk_a_fkey1" |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s3insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s3insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s3brr s3insert s3commit s1cancel s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s3brr: begin isolation level repeatable read; |
||||
step s3insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s3commit: commit; |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s3brr s3insert s3commit s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s3brr: begin isolation level repeatable read; |
||||
step s3insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s3commit: commit; |
||||
step s1c: commit; |
||||
step s2detach: <... completed> |
||||
|
||||
starting permutation: s2snitch s1brr s1s s2detach s1cancel s3vacfreeze s1s s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1brr: begin isolation level repeatable read; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s3vacfreeze: vacuum freeze pg_catalog.pg_inherits; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s1insert: insert into d4_fk values (1); |
||||
step s1c: commit; |
||||
|
||||
starting permutation: s2snitch s1b s1s s2detach s1cancel s3vacfreeze s1s s1insert s1c |
||||
step s2snitch: insert into d4_pid select pg_backend_pid(); |
||||
step s1b: begin; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
1 |
||||
2 |
||||
step s2detach: alter table d4_primary detach partition d4_primary1 concurrently; <waiting ...> |
||||
step s1cancel: select pg_cancel_backend(pid) from d4_pid; |
||||
pg_cancel_backend |
||||
|
||||
t |
||||
step s2detach: <... completed> |
||||
error in steps s1cancel s2detach: ERROR: canceling statement due to user request |
||||
step s3vacfreeze: vacuum freeze pg_catalog.pg_inherits; |
||||
step s1s: select * from d4_primary; |
||||
a |
||||
|
||||
2 |
||||
step s1insert: insert into d4_fk values (1); |
||||
ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" |
||||
step s1c: commit; |
@ -0,0 +1,69 @@ |
||||
# Test that detach partition concurrently makes the partition invisible at the |
||||
# correct time. |
||||
|
||||
setup |
||||
{ |
||||
DROP TABLE IF EXISTS d_listp, d_listp1, d_listp2; |
||||
CREATE TABLE d_listp (a int) PARTITION BY LIST(a); |
||||
CREATE TABLE d_listp1 PARTITION OF d_listp FOR VALUES IN (1); |
||||
CREATE TABLE d_listp2 PARTITION OF d_listp FOR VALUES IN (2); |
||||
INSERT INTO d_listp VALUES (1),(2); |
||||
} |
||||
|
||||
teardown { |
||||
DROP TABLE IF EXISTS d_listp, d_listp2, d_listp_foobar; |
||||
} |
||||
|
||||
session "s1" |
||||
step "s1b" { BEGIN; } |
||||
step "s1brr" { BEGIN ISOLATION LEVEL REPEATABLE READ; } |
||||
step "s1s" { SELECT * FROM d_listp; } |
||||
step "s1ins" { INSERT INTO d_listp VALUES (1); } |
||||
step "s1ins2" { INSERT INTO d_listp VALUES (2); } |
||||
step "s1prep" { PREPARE f(int) AS INSERT INTO d_listp VALUES ($1); } |
||||
step "s1prep1" { PREPARE f(int) AS INSERT INTO d_listp VALUES (1); } |
||||
step "s1prep2" { PREPARE f(int) AS INSERT INTO d_listp VALUES (2); } |
||||
step "s1exec1" { EXECUTE f(1); } |
||||
step "s1exec2" { EXECUTE f(2); } |
||||
step "s1dealloc" { DEALLOCATE f; } |
||||
step "s1c" { COMMIT; } |
||||
|
||||
session "s2" |
||||
step "s2detach" { ALTER TABLE d_listp DETACH PARTITION d_listp2 CONCURRENTLY; } |
||||
step "s2drop" { DROP TABLE d_listp2; } |
||||
|
||||
session "s3" |
||||
step "s3s" { SELECT * FROM d_listp; } |
||||
step "s3i" { SELECT relpartbound IS NULL FROM pg_class where relname = 'd_listp2'; } |
||||
step "s3ins2" { INSERT INTO d_listp VALUES (2); } |
||||
|
||||
# The transaction that detaches hangs until it sees any older transaction |
||||
# terminate, as does anybody else. |
||||
permutation "s1b" "s1s" "s2detach" "s1s" "s1c" "s1s" |
||||
|
||||
# relpartbound remains set until s1 commits |
||||
# XXX this could be timing dependent :-( |
||||
permutation "s1b" "s1s" "s2detach" "s1s" "s3s" "s3i" "s1c" "s3i" "s2drop" "s1s" |
||||
|
||||
# In read-committed mode, the partition disappears from view of concurrent |
||||
# transactions immediately. But if a write lock is held, then the detach |
||||
# has to wait. |
||||
permutation "s1b" "s1s" "s2detach" "s1ins" "s1s" "s1c" |
||||
permutation "s1b" "s1s" "s1ins2" "s2detach" "s1ins" "s1s" "s1c" |
||||
|
||||
# In repeatable-read mode, the partition remains visible until commit even |
||||
# if the to-be-detached partition is not locked for write. |
||||
permutation "s1brr" "s1s" "s2detach" "s1ins" "s1s" "s1c" |
||||
permutation "s1brr" "s1s" "s2detach" "s1s" "s1c" |
||||
|
||||
# Another process trying to acquire a write lock will be blocked behind the |
||||
# detacher |
||||
permutation "s1b" "s1ins2" "s2detach" "s3ins2" "s1c" |
||||
|
||||
# a prepared query is not blocked |
||||
permutation "s1brr" "s1prep" "s1s" "s2detach" "s1s" "s1exec1" "s3s" "s1dealloc" "s1c" |
||||
permutation "s1brr" "s1prep" "s1exec2" "s2detach" "s1s" "s1exec2" "s3s" "s1c" "s1dealloc" |
||||
permutation "s1brr" "s1prep" "s1s" "s2detach" "s1s" "s1exec2" "s1c" "s1dealloc" |
||||
permutation "s1brr" "s1prep" "s2detach" "s1s" "s1exec2" "s1c" "s1dealloc" |
||||
permutation "s1brr" "s1prep1" "s2detach" "s1s" "s1exec2" "s1c" "s1dealloc" |
||||
permutation "s1brr" "s1prep2" "s2detach" "s1s" "s1exec2" "s1c" "s1dealloc" |
@ -0,0 +1,41 @@ |
||||
# Test that detach partition concurrently makes the partition safe |
||||
# for foreign keys that reference it. |
||||
|
||||
setup |
||||
{ |
||||
DROP TABLE IF EXISTS d_lp_fk, d_lp_fk_1, d_lp_fk_2, d_lp_fk_r; |
||||
|
||||
CREATE TABLE d_lp_fk (a int PRIMARY KEY) PARTITION BY LIST(a); |
||||
CREATE TABLE d_lp_fk_1 PARTITION OF d_lp_fk FOR VALUES IN (1); |
||||
CREATE TABLE d_lp_fk_2 PARTITION OF d_lp_fk FOR VALUES IN (2); |
||||
INSERT INTO d_lp_fk VALUES (1), (2); |
||||
|
||||
CREATE TABLE d_lp_fk_r (a int references d_lp_fk); |
||||
} |
||||
|
||||
teardown { DROP TABLE IF EXISTS d_lp_fk, d_lp_fk_1, d_lp_fk_2, d_lp_fk_r; } |
||||
|
||||
session "s1" |
||||
step "s1b" { BEGIN; } |
||||
step "s1s" { SELECT * FROM d_lp_fk; } |
||||
step "s1c" { COMMIT; } |
||||
|
||||
session "s2" |
||||
step "s2d" { ALTER TABLE d_lp_fk DETACH PARTITION d_lp_fk_1 CONCURRENTLY; } |
||||
|
||||
session "s3" |
||||
step "s3b" { BEGIN; } |
||||
step "s3i1" { INSERT INTO d_lp_fk_r VALUES (1); } |
||||
step "s3i2" { INSERT INTO d_lp_fk_r VALUES (2); } |
||||
step "s3c" { COMMIT; } |
||||
|
||||
# The transaction that detaches hangs until it sees any older transaction |
||||
# terminate. |
||||
permutation "s1b" "s1s" "s2d" "s3i1" "s1c" |
||||
permutation "s1b" "s1s" "s2d" "s3i2" "s3i2" "s1c" |
||||
|
||||
permutation "s1b" "s1s" "s3i1" "s2d" "s1c" |
||||
permutation "s1b" "s1s" "s3i2" "s2d" "s1c" |
||||
|
||||
# what if s3 has an uncommitted insertion? |
||||
permutation "s1b" "s1s" "s3b" "s2d" "s3i1" "s1c" "s3c" |
@ -0,0 +1,66 @@ |
||||
# Try various things to happen to a partition with an incomplete detach |
||||
|
||||
setup |
||||
{ |
||||
CREATE TABLE d3_listp (a int) PARTITION BY LIST(a); |
||||
CREATE TABLE d3_listp1 PARTITION OF d3_listp FOR VALUES IN (1); |
||||
CREATE TABLE d3_pid (pid int); |
||||
INSERT INTO d3_listp VALUES (1); |
||||
} |
||||
|
||||
teardown { |
||||
DROP TABLE IF EXISTS d3_listp, d3_listp1, d3_pid; |
||||
} |
||||
|
||||
session "s1" |
||||
step "s1b" { BEGIN; } |
||||
step "s1brr" { BEGIN ISOLATION LEVEL REPEATABLE READ; } |
||||
step "s1s" { SELECT * FROM d3_listp; } |
||||
step "s1spart" { SELECT * FROM d3_listp1; } |
||||
step "s1cancel" { SELECT pg_cancel_backend(pid) FROM d3_pid; } |
||||
step "s1c" { COMMIT; } |
||||
step "s1alter" { ALTER TABLE d3_listp1 ALTER a DROP NOT NULL; } |
||||
step "s1insert" { INSERT INTO d3_listp VALUES (1); } |
||||
step "s1insertpart" { INSERT INTO d3_listp1 VALUES (1); } |
||||
step "s1drop" { DROP TABLE d3_listp; } |
||||
step "s1droppart" { DROP TABLE d3_listp1; } |
||||
step "s1trunc" { TRUNCATE TABLE d3_listp; } |
||||
step "s1list" { SELECT relname FROM pg_catalog.pg_class |
||||
WHERE relname LIKE 'd3_listp%' ORDER BY 1; } |
||||
step "s1describe" { SELECT 'd3_listp' AS root, * FROM pg_partition_tree('d3_listp') |
||||
UNION ALL SELECT 'd3_listp1', * FROM pg_partition_tree('d3_listp1'); } |
||||
|
||||
session "s2" |
||||
step "s2begin" { BEGIN; } |
||||
step "s2snitch" { INSERT INTO d3_pid SELECT pg_backend_pid(); } |
||||
step "s2detach" { ALTER TABLE d3_listp DETACH PARTITION d3_listp1 CONCURRENTLY; } |
||||
step "s2detachfinal" { ALTER TABLE d3_listp DETACH PARTITION d3_listp1 FINALIZE; } |
||||
step "s2drop" { DROP TABLE d3_listp1; } |
||||
step "s2commit" { COMMIT; } |
||||
|
||||
# Try various things while the partition is in "being detached" state, with |
||||
# no session waiting. |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s1describe" "s1alter" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1brr" "s1s" "s2detach" "s1cancel" "s1insert" "s1c" "s1spart" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s1insertpart" |
||||
# "drop" here does both tables |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s1drop" "s1list" |
||||
# "truncate" only does parent, not partition |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s1trunc" "s1spart" |
||||
|
||||
# When a partition with incomplete detach is dropped, we grab lock on parent too. |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s2begin" "s2drop" "s1s" "s2commit" |
||||
|
||||
# Partially detach, then select and try to complete the detach. Reading |
||||
# from partition blocks (AEL is required on partition); reading from parent |
||||
# does not block. |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s1b" "s1spart" "s2detachfinal" "s1c" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s1b" "s1s" "s2detachfinal" "s1c" |
||||
|
||||
# DETACH FINALIZE in a transaction block. No insert/select on the partition |
||||
# is allowed concurrently with that. |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s1b" "s1spart" "s2detachfinal" "s1c" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s2begin" "s2detachfinal" "s2commit" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s2begin" "s2detachfinal" "s1spart" "s2commit" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1c" "s2begin" "s2detachfinal" "s1insertpart" "s2commit" |
@ -0,0 +1,74 @@ |
||||
# This test exercises behavior of foreign keys in the face of concurrent |
||||
# detach of partitions in the referenced table. |
||||
# (The cases where the detaching transaction is cancelled is interesting |
||||
# because the locking situation is completely different. I didn't verify |
||||
# that keeping both variants adds any extra coverage.) |
||||
setup { |
||||
drop table if exists d4_primary, d4_primary1, d4_fk, d4_pid; |
||||
create table d4_primary (a int primary key) partition by list (a); |
||||
create table d4_primary1 partition of d4_primary for values in (1); |
||||
create table d4_primary2 partition of d4_primary for values in (2); |
||||
insert into d4_primary values (1); |
||||
insert into d4_primary values (2); |
||||
create table d4_fk (a int references d4_primary); |
||||
insert into d4_fk values (2); |
||||
create table d4_pid (pid int); |
||||
} |
||||
|
||||
session "s1" |
||||
step "s1b" { begin; } |
||||
step "s1brr" { begin isolation level repeatable read; } |
||||
step "s1s" { select * from d4_primary; } |
||||
step "s1cancel" { select pg_cancel_backend(pid) from d4_pid; } |
||||
step "s1insert" { insert into d4_fk values (1); } |
||||
step "s1c" { commit; } |
||||
step "s1declare" { declare f cursor for select * from d4_primary; } |
||||
step "s1declare2" { declare f cursor for select * from d4_fk where a = 2; } |
||||
step "s1fetchall" { fetch all from f; } |
||||
step "s1fetchone" { fetch 1 from f; } |
||||
step "s1updcur" { update d4_fk set a = 1 where current of f; } |
||||
step "s1svpt" { savepoint f; } |
||||
step "s1rollback" { rollback to f; } |
||||
|
||||
session "s2" |
||||
step "s2snitch" { insert into d4_pid select pg_backend_pid(); } |
||||
step "s2detach" { alter table d4_primary detach partition d4_primary1 concurrently; } |
||||
|
||||
session "s3" |
||||
step "s3brr" { begin isolation level repeatable read; } |
||||
step "s3insert" { insert into d4_fk values (1); } |
||||
step "s3commit" { commit; } |
||||
step "s3vacfreeze" { vacuum freeze pg_catalog.pg_inherits; } |
||||
|
||||
# Trying to insert into a partially detached partition is rejected |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1insert" "s1c" |
||||
# ... even under REPEATABLE READ mode. |
||||
permutation "s2snitch" "s1brr" "s1s" "s2detach" "s1cancel" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1brr" "s1s" "s2detach" "s1insert" "s1c" |
||||
|
||||
# If you read the referenced table using a cursor, you can see a row that the |
||||
# RI query does not see. |
||||
permutation "s2snitch" "s1b" "s1declare" "s2detach" "s1cancel" "s1fetchall" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1b" "s1declare" "s2detach" "s1fetchall" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1b" "s1declare" "s2detach" "s1cancel" "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c" |
||||
permutation "s2snitch" "s1b" "s1declare" "s2detach" "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c" |
||||
permutation "s2snitch" "s1b" "s2detach" "s1declare" "s1cancel" "s1fetchall" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1b" "s2detach" "s1declare" "s1fetchall" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1b" "s2detach" "s1declare" "s1cancel" "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c" |
||||
permutation "s2snitch" "s1b" "s2detach" "s1declare" "s1svpt" "s1insert" "s1rollback" "s1fetchall" "s1c" |
||||
|
||||
# Creating the referencing row using a cursor |
||||
permutation "s2snitch" "s1brr" "s1declare2" "s1fetchone" "s2detach" "s1cancel" "s1updcur" "s1c" |
||||
permutation "s2snitch" "s1brr" "s1declare2" "s1fetchone" "s2detach" "s1updcur" "s1c" |
||||
permutation "s2snitch" "s1brr" "s1declare2" "s1fetchone" "s1updcur" "s2detach" "s1c" |
||||
|
||||
# Try reading the table from an independent session. |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s3insert" "s1c" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s3brr" "s3insert" "s3commit" "s1cancel" "s1c" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s3brr" "s3insert" "s3commit" "s1c" |
||||
|
||||
# Try one where we VACUUM FREEZE pg_inherits (to verify that xmin change is |
||||
# handled correctly). |
||||
permutation "s2snitch" "s1brr" "s1s" "s2detach" "s1cancel" "s3vacfreeze" "s1s" "s1insert" "s1c" |
||||
permutation "s2snitch" "s1b" "s1s" "s2detach" "s1cancel" "s3vacfreeze" "s1s" "s1insert" "s1c" |
@ -0,0 +1,175 @@ |
||||
Parsed test spec with 3 sessions |
||||
|
||||
starting permutation: s3lock s1b s1exec s2remp s3check s3unlock s3check s1c |
||||
step s3lock: SELECT pg_advisory_lock(12543); |
||||
pg_advisory_lock |
||||
|
||||
|
||||
step s1b: BEGIN; |
||||
step s1exec: SELECT * FROM partrem WHERE a <> 1 AND a <> (SELECT 3); <waiting ...> |
||||
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...> |
||||
step s3check: SELECT * FROM partrem; |
||||
a b |
||||
|
||||
1 ABC |
||||
3 DEF |
||||
step s3unlock: SELECT pg_advisory_unlock(12543); |
||||
pg_advisory_unlock |
||||
|
||||
t |
||||
step s1exec: <... completed> |
||||
a b |
||||
|
||||
2 JKL |
||||
step s3check: SELECT * FROM partrem; |
||||
a b |
||||
|
||||
1 ABC |
||||
3 DEF |
||||
step s1c: COMMIT; |
||||
step s2remp: <... completed> |
||||
|
||||
starting permutation: s3lock s1brr s1exec s2remp s3check s3unlock s3check s1c |
||||
step s3lock: SELECT pg_advisory_lock(12543); |
||||
pg_advisory_lock |
||||
|
||||
|
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1exec: SELECT * FROM partrem WHERE a <> 1 AND a <> (SELECT 3); <waiting ...> |
||||
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...> |
||||
step s3check: SELECT * FROM partrem; |
||||
a b |
||||
|
||||
1 ABC |
||||
3 DEF |
||||
step s3unlock: SELECT pg_advisory_unlock(12543); |
||||
pg_advisory_unlock |
||||
|
||||
t |
||||
step s1exec: <... completed> |
||||
a b |
||||
|
||||
2 JKL |
||||
step s3check: SELECT * FROM partrem; |
||||
a b |
||||
|
||||
1 ABC |
||||
3 DEF |
||||
step s1c: COMMIT; |
||||
step s2remp: <... completed> |
||||
|
||||
starting permutation: s3lock s1b s1exec2 s2remp s3unlock s1c |
||||
step s3lock: SELECT pg_advisory_lock(12543); |
||||
pg_advisory_lock |
||||
|
||||
|
||||
step s1b: BEGIN; |
||||
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...> |
||||
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...> |
||||
step s3unlock: SELECT pg_advisory_unlock(12543); |
||||
pg_advisory_unlock |
||||
|
||||
t |
||||
step s1exec2: <... completed> |
||||
a b |
||||
|
||||
3 DEF |
||||
step s1c: COMMIT; |
||||
step s2remp: <... completed> |
||||
|
||||
starting permutation: s3lock s1brr s1exec2 s2remp s3unlock s1c |
||||
step s3lock: SELECT pg_advisory_lock(12543); |
||||
pg_advisory_lock |
||||
|
||||
|
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1exec2: SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; <waiting ...> |
||||
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...> |
||||
step s3unlock: SELECT pg_advisory_unlock(12543); |
||||
pg_advisory_unlock |
||||
|
||||
t |
||||
step s1exec2: <... completed> |
||||
a b |
||||
|
||||
3 DEF |
||||
step s1c: COMMIT; |
||||
step s2remp: <... completed> |
||||
|
||||
starting permutation: s3lock s1brr s1prepare s2remp s1execprep s3unlock s1check s1c s1check s1dealloc |
||||
step s3lock: SELECT pg_advisory_lock(12543); |
||||
pg_advisory_lock |
||||
|
||||
|
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI'); |
||||
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...> |
||||
step s1execprep: EXECUTE ins(2); <waiting ...> |
||||
step s3unlock: SELECT pg_advisory_unlock(12543); |
||||
pg_advisory_unlock |
||||
|
||||
t |
||||
step s1execprep: <... completed> |
||||
step s1check: SELECT * FROM partrem WHERE b = 'GHI'; |
||||
a b |
||||
|
||||
2 GHI |
||||
step s1c: COMMIT; |
||||
step s2remp: <... completed> |
||||
step s1check: SELECT * FROM partrem WHERE b = 'GHI'; |
||||
a b |
||||
|
||||
step s1dealloc: DEALLOCATE ins; |
||||
|
||||
starting permutation: s1brr s1prepare s2remp s3lock s1execprep s3unlock s1check s1c s1check s1dealloc |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI'); |
||||
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...> |
||||
step s3lock: SELECT pg_advisory_lock(12543); |
||||
pg_advisory_lock |
||||
|
||||
|
||||
step s1execprep: EXECUTE ins(2); <waiting ...> |
||||
step s3unlock: SELECT pg_advisory_unlock(12543); |
||||
pg_advisory_unlock |
||||
|
||||
t |
||||
step s1execprep: <... completed> |
||||
step s1check: SELECT * FROM partrem WHERE b = 'GHI'; |
||||
a b |
||||
|
||||
2 GHI |
||||
step s1c: COMMIT; |
||||
step s2remp: <... completed> |
||||
step s1check: SELECT * FROM partrem WHERE b = 'GHI'; |
||||
a b |
||||
|
||||
step s1dealloc: DEALLOCATE ins; |
||||
|
||||
starting permutation: s1brr s1check s3lock s2remp s1prepare s1execprep s3unlock s1check s1c s1check s1dealloc |
||||
step s1brr: BEGIN ISOLATION LEVEL REPEATABLE READ; |
||||
step s1check: SELECT * FROM partrem WHERE b = 'GHI'; |
||||
a b |
||||
|
||||
step s3lock: SELECT pg_advisory_lock(12543); |
||||
pg_advisory_lock |
||||
|
||||
|
||||
step s2remp: ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; <waiting ...> |
||||
step s1prepare: PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI'); |
||||
step s1execprep: EXECUTE ins(2); <waiting ...> |
||||
step s3unlock: SELECT pg_advisory_unlock(12543); |
||||
pg_advisory_unlock |
||||
|
||||
t |
||||
step s1execprep: <... completed> |
||||
step s1check: SELECT * FROM partrem WHERE b = 'GHI'; |
||||
a b |
||||
|
||||
2 GHI |
||||
step s1c: COMMIT; |
||||
step s2remp: <... completed> |
||||
step s1check: SELECT * FROM partrem WHERE b = 'GHI'; |
||||
a b |
||||
|
||||
step s1dealloc: DEALLOCATE ins; |
@ -0,0 +1,58 @@ |
||||
# Test removal of a partition with less-than-exclusive locking. |
||||
|
||||
setup |
||||
{ |
||||
CREATE TABLE partrem (a int, b text) PARTITION BY LIST(a); |
||||
CREATE TABLE partrem1 PARTITION OF partrem FOR VALUES IN (1); |
||||
CREATE TABLE partrem2 PARTITION OF partrem FOR VALUES IN (2); |
||||
CREATE TABLE partrem3 PARTITION OF partrem FOR VALUES IN (3); |
||||
INSERT INTO partrem VALUES (1, 'ABC'); |
||||
INSERT INTO partrem VALUES (2, 'JKL'); |
||||
INSERT INTO partrem VALUES (3, 'DEF'); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP TABLE IF EXISTS partrem, partrem2; |
||||
} |
||||
|
||||
session "s1" |
||||
setup { LOAD 'delay_execution'; |
||||
SET delay_execution.post_planning_lock_id = 12543; } |
||||
step "s1b" { BEGIN; } |
||||
step "s1brr" { BEGIN ISOLATION LEVEL REPEATABLE READ; } |
||||
step "s1exec" { SELECT * FROM partrem WHERE a <> 1 AND a <> (SELECT 3); } |
||||
step "s1exec2" { SELECT * FROM partrem WHERE a <> (SELECT 2) AND a <> 1; } |
||||
step "s1prepare" { PREPARE ins AS INSERT INTO partrem VALUES ($1, 'GHI'); } |
||||
step "s1execprep" { EXECUTE ins(2); } |
||||
step "s1check" { SELECT * FROM partrem WHERE b = 'GHI'; } |
||||
step "s1c" { COMMIT; } |
||||
step "s1dealloc" { DEALLOCATE ins; } |
||||
|
||||
session "s2" |
||||
step "s2remp" { ALTER TABLE partrem DETACH PARTITION partrem2 CONCURRENTLY; } |
||||
|
||||
session "s3" |
||||
step "s3lock" { SELECT pg_advisory_lock(12543); } |
||||
step "s3unlock" { SELECT pg_advisory_unlock(12543); } |
||||
step "s3check" { SELECT * FROM partrem; } |
||||
|
||||
# The SELECT will be planned with all three partitions shown above, |
||||
# of which we expect partrem1 to be pruned at planning and partrem3 at |
||||
# execution. Then we'll block, and by the time the query is actually |
||||
# executed, detach of partrem2 is already underway (so its row doesn't |
||||
# show up in s3's result), but we expect its row to still appear in the |
||||
# result for s1. |
||||
permutation "s3lock" "s1b" "s1exec" "s2remp" "s3check" "s3unlock" "s3check" "s1c" |
||||
permutation "s3lock" "s1brr" "s1exec" "s2remp" "s3check" "s3unlock" "s3check" "s1c" |
||||
|
||||
# In this case we're testing that after pruning partrem2 at runtime, the |
||||
# query still works correctly. |
||||
permutation "s3lock" "s1b" "s1exec2" "s2remp" "s3unlock" "s1c" |
||||
permutation "s3lock" "s1brr" "s1exec2" "s2remp" "s3unlock" "s1c" |
||||
|
||||
# In this case we test that an insert that's prepared in repeatable read |
||||
# mode still works after detaching. |
||||
permutation "s3lock" "s1brr" "s1prepare" "s2remp" "s1execprep" "s3unlock" "s1check" "s1c" "s1check" "s1dealloc" |
||||
permutation "s1brr" "s1prepare" "s2remp" "s3lock" "s1execprep" "s3unlock" "s1check" "s1c" "s1check" "s1dealloc" |
||||
permutation "s1brr" "s1check" "s3lock" "s2remp" "s1prepare" "s1execprep" "s3unlock" "s1check" "s1c" "s1check" "s1dealloc" |
Loading…
Reference in new issue