From 166cc082b9d652e186df4ef7b6c41976a22e55a8 Mon Sep 17 00:00:00 2001 From: amit Date: Mon, 7 Aug 2017 10:51:47 +0900 Subject: [PATCH 1/2] Teach ValidatePartitionConstraints to skip validation in more cases In cases where the table being attached is a partitioned table and the table itself does not have constraints that would allow validation on the whole table to be skipped, we can still skip the validations of individual partitions if they each happen to have the requisite constraints. Idea by Robert Haas. --- src/backend/commands/tablecmds.c | 26 +++++++++++++++++++++++--- src/test/regress/expected/alter_table.out | 17 +++++++++++++++-- src/test/regress/sql/alter_table.sql | 10 ++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 563bcda30c..2d4dcd7556 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -13635,9 +13635,14 @@ ValidatePartitionConstraints(List **wqueue, Relation scanrel, */ if (PartConstraintImpliedByRelConstraint(scanrel, partConstraint)) { - ereport(INFO, - (errmsg("partition constraint for table \"%s\" is implied by existing constraints", - RelationGetRelationName(scanrel)))); + if (!validate_default) + ereport(INFO, + (errmsg("partition constraint for table \"%s\" is implied by existing constraints", + RelationGetRelationName(scanrel)))); + else + ereport(INFO, + (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints", + RelationGetRelationName(scanrel)))); return; } @@ -13678,6 +13683,21 @@ ValidatePartitionConstraints(List **wqueue, Relation scanrel, /* There can never be a whole-row reference here */ if (found_whole_row) elog(ERROR, "unexpected whole-row reference found in partition key"); + + /* Can we skip scanning this part_rel? */ + if (PartConstraintImpliedByRelConstraint(part_rel, my_partconstr)) + { + if (!validate_default) + ereport(INFO, + (errmsg("partition constraint for table \"%s\" is implied by existing constraints", + RelationGetRelationName(part_rel)))); + else + ereport(INFO, + (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints", + RelationGetRelationName(part_rel)))); + heap_close(part_rel, NoLock); + continue; + } } /* Grab a work queue entry. */ diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 0478a8ac60..fc644c12ae 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3436,7 +3436,7 @@ ALTER TABLE part_7 ATTACH PARTITION part_7_a_null FOR VALUES IN ('a', null); INFO: partition constraint for table "part_7_a_null" is implied by existing constraints ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7); INFO: partition constraint for table "part_7" is implied by existing constraints -INFO: partition constraint for table "list_parted2_def" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def" is implied by existing constraints -- Same example, but check this time that the constraint correctly detects -- violating rows ALTER TABLE list_parted2 DETACH PARTITION part_7; @@ -3450,7 +3450,7 @@ SELECT tableoid::regclass, a, b FROM part_7 order by a; (2 rows) ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7); -INFO: partition constraint for table "list_parted2_def" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def" is implied by existing constraints ERROR: partition constraint is violated by some row -- check that leaf partitions of default partition are scanned when -- attaching a partitioned table. @@ -3464,6 +3464,19 @@ ERROR: updated partition constraint for default partition would be violated by -- should be ok after deleting the bad row DELETE FROM part5_def_p1 WHERE b = 'y'; ALTER TABLE part_5 ATTACH PARTITION part5_p1 FOR VALUES IN ('y'); +-- If the partitioned table being attached does not have a constraint that +-- would allow validation scan to be skipped, but an individual partition +-- does, then the partition's validation scan is skipped. Note that the +-- following leaf partition only allows rows that have a = 7 (and b = 'b' but +-- that's irrelevant). +CREATE TABLE part_7_b PARTITION OF part_7 ( + CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7) +) FOR VALUES IN ('b'); +-- The faulting row in part_7_a_null will still cause the command to fail +ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7); +INFO: partition constraint for table "part_7_b" is implied by existing constraints +INFO: updated partition constraint for default partition "list_parted2_def" is implied by existing constraints +ERROR: partition constraint is violated by some row -- check that the table being attached is not already a partition ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); ERROR: "part_2" is already a partition diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 37cca72620..d296314ca9 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2277,6 +2277,16 @@ ALTER TABLE part_5 ATTACH PARTITION part5_p1 FOR VALUES IN ('y'); -- should be ok after deleting the bad row DELETE FROM part5_def_p1 WHERE b = 'y'; ALTER TABLE part_5 ATTACH PARTITION part5_p1 FOR VALUES IN ('y'); +-- If the partitioned table being attached does not have a constraint that +-- would allow validation scan to be skipped, but an individual partition +-- does, then the partition's validation scan is skipped. Note that the +-- following leaf partition only allows rows that have a = 7 (and b = 'b' but +-- that's irrelevant). +CREATE TABLE part_7_b PARTITION OF part_7 ( + CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7) +) FOR VALUES IN ('b'); +-- The faulting row in part_7_a_null will still cause the command to fail +ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7); -- check that the table being attached is not already a partition ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2); -- 2.11.0