mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Fix TRUNCATE .. CASCADE on partitions
When running TRUNCATE CASCADE on a child of a partitioned table referenced by another partitioned table, the truncate was not applied to partitions of the referencing table; this could leave rows violating the constraint in the referencing partitioned table. Repair by walking the pg_constraint chain all the way up to the topmost referencing table. Note: any partitioned tables containing FKs that reference other partitioned tables should be checked for possible violating rows, if TRUNCATE has occurred in partitions of the referenced table. Reported-by: Christophe Courtois Author: Jehan-Guillaume de Rorthais Discussion: https://postgr.es/m/20200204183906.115f693e@firost
This commit is contained in:
@ -542,3 +542,53 @@ SELECT * FROM tp_chk_data();
|
||||
|
||||
DROP TABLE truncprim, truncpart;
|
||||
DROP FUNCTION tp_ins_data(), tp_chk_data();
|
||||
-- test cascade when referencing a partitioned table
|
||||
CREATE TABLE trunc_a (a INT PRIMARY KEY) PARTITION BY RANGE (a);
|
||||
CREATE TABLE trunc_a1 PARTITION OF trunc_a FOR VALUES FROM (0) TO (10);
|
||||
CREATE TABLE trunc_a2 PARTITION OF trunc_a FOR VALUES FROM (10) TO (20)
|
||||
PARTITION BY RANGE (a);
|
||||
CREATE TABLE trunc_a21 PARTITION OF trunc_a2 FOR VALUES FROM (10) TO (12);
|
||||
CREATE TABLE trunc_a22 PARTITION OF trunc_a2 FOR VALUES FROM (12) TO (16);
|
||||
CREATE TABLE trunc_a2d PARTITION OF trunc_a2 DEFAULT;
|
||||
CREATE TABLE trunc_a3 PARTITION OF trunc_a FOR VALUES FROM (20) TO (30);
|
||||
INSERT INTO trunc_a VALUES (0), (5), (10), (15), (20), (25);
|
||||
-- truncate a partition cascading to a table
|
||||
CREATE TABLE ref_b (
|
||||
b INT PRIMARY KEY,
|
||||
a INT REFERENCES trunc_a(a) ON DELETE CASCADE
|
||||
);
|
||||
INSERT INTO ref_b VALUES (10, 0), (50, 5), (100, 10), (150, 15);
|
||||
TRUNCATE TABLE trunc_a1 CASCADE;
|
||||
NOTICE: truncate cascades to table "ref_b"
|
||||
SELECT a FROM ref_b;
|
||||
a
|
||||
---
|
||||
(0 rows)
|
||||
|
||||
DROP TABLE ref_b;
|
||||
-- truncate a partition cascading to a partitioned table
|
||||
CREATE TABLE ref_c (
|
||||
c INT PRIMARY KEY,
|
||||
a INT REFERENCES trunc_a(a) ON DELETE CASCADE
|
||||
) PARTITION BY RANGE (c);
|
||||
CREATE TABLE ref_c1 PARTITION OF ref_c FOR VALUES FROM (100) TO (200);
|
||||
CREATE TABLE ref_c2 PARTITION OF ref_c FOR VALUES FROM (200) TO (300);
|
||||
INSERT INTO ref_c VALUES (100, 10), (150, 15), (200, 20), (250, 25);
|
||||
TRUNCATE TABLE trunc_a21 CASCADE;
|
||||
NOTICE: truncate cascades to table "ref_c"
|
||||
NOTICE: truncate cascades to table "ref_c1"
|
||||
NOTICE: truncate cascades to table "ref_c2"
|
||||
SELECT a as "from table ref_c" FROM ref_c;
|
||||
from table ref_c
|
||||
------------------
|
||||
(0 rows)
|
||||
|
||||
SELECT a as "from table trunc_a" FROM trunc_a ORDER BY a;
|
||||
from table trunc_a
|
||||
--------------------
|
||||
15
|
||||
20
|
||||
25
|
||||
(3 rows)
|
||||
|
||||
DROP TABLE trunc_a, ref_c;
|
||||
|
@ -289,3 +289,41 @@ TRUNCATE TABLE truncpart;
|
||||
SELECT * FROM tp_chk_data();
|
||||
DROP TABLE truncprim, truncpart;
|
||||
DROP FUNCTION tp_ins_data(), tp_chk_data();
|
||||
|
||||
-- test cascade when referencing a partitioned table
|
||||
CREATE TABLE trunc_a (a INT PRIMARY KEY) PARTITION BY RANGE (a);
|
||||
CREATE TABLE trunc_a1 PARTITION OF trunc_a FOR VALUES FROM (0) TO (10);
|
||||
CREATE TABLE trunc_a2 PARTITION OF trunc_a FOR VALUES FROM (10) TO (20)
|
||||
PARTITION BY RANGE (a);
|
||||
CREATE TABLE trunc_a21 PARTITION OF trunc_a2 FOR VALUES FROM (10) TO (12);
|
||||
CREATE TABLE trunc_a22 PARTITION OF trunc_a2 FOR VALUES FROM (12) TO (16);
|
||||
CREATE TABLE trunc_a2d PARTITION OF trunc_a2 DEFAULT;
|
||||
CREATE TABLE trunc_a3 PARTITION OF trunc_a FOR VALUES FROM (20) TO (30);
|
||||
INSERT INTO trunc_a VALUES (0), (5), (10), (15), (20), (25);
|
||||
|
||||
-- truncate a partition cascading to a table
|
||||
CREATE TABLE ref_b (
|
||||
b INT PRIMARY KEY,
|
||||
a INT REFERENCES trunc_a(a) ON DELETE CASCADE
|
||||
);
|
||||
INSERT INTO ref_b VALUES (10, 0), (50, 5), (100, 10), (150, 15);
|
||||
|
||||
TRUNCATE TABLE trunc_a1 CASCADE;
|
||||
SELECT a FROM ref_b;
|
||||
|
||||
DROP TABLE ref_b;
|
||||
|
||||
-- truncate a partition cascading to a partitioned table
|
||||
CREATE TABLE ref_c (
|
||||
c INT PRIMARY KEY,
|
||||
a INT REFERENCES trunc_a(a) ON DELETE CASCADE
|
||||
) PARTITION BY RANGE (c);
|
||||
CREATE TABLE ref_c1 PARTITION OF ref_c FOR VALUES FROM (100) TO (200);
|
||||
CREATE TABLE ref_c2 PARTITION OF ref_c FOR VALUES FROM (200) TO (300);
|
||||
INSERT INTO ref_c VALUES (100, 10), (150, 15), (200, 20), (250, 25);
|
||||
|
||||
TRUNCATE TABLE trunc_a21 CASCADE;
|
||||
SELECT a as "from table ref_c" FROM ref_c;
|
||||
SELECT a as "from table trunc_a" FROM trunc_a ORDER BY a;
|
||||
|
||||
DROP TABLE trunc_a, ref_c;
|
||||
|
Reference in New Issue
Block a user