agora inbox for pgsql-hackers@postgresql.orghelp / color / mirror / Atom feed
[PATCH 1/2] Allow dropping partitioned table without CASCADE 7+ messages / 2 participants [nested] [flat]
* [PATCH 1/2] Allow dropping partitioned table without CASCADE @ 2017-02-16 06:56 amit <amitlangote09@gmail.com> 0 siblings, 0 replies; 7+ messages in thread From: amit @ 2017-02-16 06:56 UTC (permalink / raw) Currently, a normal dependency is created between a inheritance parent and child when creating the child. That means one must specify CASCADE to drop the parent table if a child table exists. When creating partitions as inheritance children, create auto dependency instead, so that partitions are dropped automatically when the parent is dropped i.e., without specifying CASCADE. --- src/backend/commands/tablecmds.c | 26 ++++++++++++++++++-------- src/test/regress/expected/alter_table.out | 10 ++++------ src/test/regress/expected/create_table.out | 9 ++------- src/test/regress/expected/inherit.out | 18 ------------------ src/test/regress/expected/insert.out | 7 ++----- src/test/regress/expected/update.out | 5 ----- src/test/regress/sql/alter_table.sql | 10 ++++------ src/test/regress/sql/create_table.sql | 9 ++------- src/test/regress/sql/insert.sql | 7 ++----- 9 files changed, 34 insertions(+), 67 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3cea220421..31b50ad77f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -289,9 +289,11 @@ static List *MergeAttributes(List *schema, List *supers, char relpersistence, static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); -static void StoreCatalogInheritance(Oid relationId, List *supers); +static void StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition); static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation); + int16 seqNumber, Relation inhRelation, + bool child_is_partition); static int findAttrByName(const char *attributeName, List *schema); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved); @@ -725,7 +727,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, typaddress); /* Store inheritance information for new rel. */ - StoreCatalogInheritance(relationId, inheritOids); + StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); /* * We must bump the command counter to make the newly-created relation @@ -2240,7 +2242,8 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr) * supers is a list of the OIDs of the new relation's direct ancestors. */ static void -StoreCatalogInheritance(Oid relationId, List *supers) +StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition) { Relation relation; int16 seqNumber; @@ -2270,7 +2273,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) { Oid parentOid = lfirst_oid(entry); - StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation); + StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation, + child_is_partition); seqNumber++; } @@ -2283,7 +2287,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) */ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation) + int16 seqNumber, Relation inhRelation, + bool child_is_partition) { TupleDesc desc = RelationGetDescr(inhRelation); Datum values[Natts_pg_inherits]; @@ -2317,7 +2322,10 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid, childobject.objectId = relationId; childobject.objectSubId = 0; - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + if (!child_is_partition) + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + else + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); /* * Post creation hook of this inheritance. Since object_access_hook @@ -10744,7 +10752,9 @@ CreateInheritance(Relation child_rel, Relation parent_rel) StoreCatalogInheritance1(RelationGetRelid(child_rel), RelationGetRelid(parent_rel), inhseqno + 1, - catalogRelation); + catalogRelation, + parent_rel->rd_rel->relkind == + RELKIND_PARTITIONED_TABLE); /* Now we're done with pg_inherits */ heap_close(catalogRelation, RowExclusiveLock); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index e84af67fb2..ca66158ee3 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3339,10 +3339,8 @@ ALTER TABLE list_parted2 DROP COLUMN b; ERROR: cannot drop column named in partition key ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; ERROR: cannot alter type of column named in partition key --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int, a int not null) partition by range (b); @@ -3371,5 +3369,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); ERROR: partition constraint is violated by some row --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 20eb3d35f9..c07a474b3d 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -667,10 +667,5 @@ Check constraints: "check_a" CHECK (length(a) > 0) Number of partitions: 3 (Use \d+ to list them.) --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index a8c8b28a75..623aa1db93 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1844,22 +1844,4 @@ explain (costs off) select * from range_list_parted where a >= 30; (11 rows) drop table list_parted cascade; -NOTICE: drop cascades to 3 other objects -DETAIL: drop cascades to table part_ab_cd -drop cascades to table part_ef_gh -drop cascades to table part_null_xy drop table range_list_parted cascade; -NOTICE: drop cascades to 13 other objects -DETAIL: drop cascades to table part_1_10 -drop cascades to table part_1_10_ab -drop cascades to table part_1_10_cd -drop cascades to table part_10_20 -drop cascades to table part_10_20_ab -drop cascades to table part_10_20_cd -drop cascades to table part_21_30 -drop cascades to table part_21_30_ab -drop cascades to table part_21_30_cd -drop cascades to table part_40_inf -drop cascades to table part_40_inf_ab -drop cascades to table part_40_inf_cd -drop cascades to table part_40_inf_null diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index 81af3ef497..31cfa4e76e 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -314,10 +314,7 @@ select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_p (9 rows) -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int not null, a int not null) partition by range ((b+0)); @@ -387,4 +384,4 @@ with ins (a, b, c) as (5 rows) -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index a1e9255450..af0d5bfffe 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -220,8 +220,3 @@ DETAIL: Failing row contains (b, 9). update range_parted set b = b + 1 where b = 10; -- cleanup drop table range_parted cascade; -NOTICE: drop cascades to 4 other objects -DETAIL: drop cascades to table part_a_1_a_10 -drop cascades to table part_a_10_a_20 -drop cascades to table part_b_1_b_10 -drop cascades to table part_b_10_b_20 diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index a403fd8cb4..fbcc739f41 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2199,10 +2199,8 @@ ALTER TABLE part_2 INHERIT inh_test; ALTER TABLE list_parted2 DROP COLUMN b; ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -2227,5 +2225,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index f41dd71475..1f0fa8e16d 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -595,10 +595,5 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); -- returned. \d parted --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 454e1ce2e7..dfdc24eba8 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -186,10 +186,7 @@ insert into list_parted (b) values (1); select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -241,4 +238,4 @@ with ins (a, b, c) as select a, b, min(c), max(c) from ins group by a, b order by 1; -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; -- 2.11.0 --------------379EDB3A18529E0BEF728289 Content-Type: text/x-diff; name="0002-Add-regression-tests-foreign-partition-DDL.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-Add-regression-tests-foreign-partition-DDL.patch" ^ permalink raw reply [nested|flat] 7+ messages in thread
* [PATCH] Allow dropping partitioned table without CASCADE @ 2017-02-16 06:56 amit <amitlangote09@gmail.com> 0 siblings, 0 replies; 7+ messages in thread From: amit @ 2017-02-16 06:56 UTC (permalink / raw) Currently, a normal dependency is created between a inheritance parent and child when creating the child. That means one must specify CASCADE to drop the parent table if a child table exists. When creating partitions as inheritance children, create auto dependency instead, so that partitions are dropped automatically when the parent is dropped i.e., without specifying CASCADE. --- src/backend/commands/tablecmds.c | 26 ++++++++++++++++++-------- src/test/regress/expected/alter_table.out | 10 ++++------ src/test/regress/expected/create_table.out | 9 ++------- src/test/regress/expected/inherit.out | 18 ------------------ src/test/regress/expected/insert.out | 7 ++----- src/test/regress/expected/update.out | 5 ----- src/test/regress/sql/alter_table.sql | 10 ++++------ src/test/regress/sql/create_table.sql | 9 ++------- src/test/regress/sql/insert.sql | 7 ++----- 9 files changed, 34 insertions(+), 67 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f33aa70da6..27b6556a71 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -289,9 +289,11 @@ static List *MergeAttributes(List *schema, List *supers, char relpersistence, static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); -static void StoreCatalogInheritance(Oid relationId, List *supers); +static void StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition); static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation); + int16 seqNumber, Relation inhRelation, + bool child_is_partition); static int findAttrByName(const char *attributeName, List *schema); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved); @@ -730,7 +732,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, typaddress); /* Store inheritance information for new rel. */ - StoreCatalogInheritance(relationId, inheritOids); + StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); /* * We must bump the command counter to make the newly-created relation @@ -2245,7 +2247,8 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr) * supers is a list of the OIDs of the new relation's direct ancestors. */ static void -StoreCatalogInheritance(Oid relationId, List *supers) +StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition) { Relation relation; int16 seqNumber; @@ -2275,7 +2278,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) { Oid parentOid = lfirst_oid(entry); - StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation); + StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation, + child_is_partition); seqNumber++; } @@ -2288,7 +2292,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) */ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation) + int16 seqNumber, Relation inhRelation, + bool child_is_partition) { TupleDesc desc = RelationGetDescr(inhRelation); Datum values[Natts_pg_inherits]; @@ -2322,7 +2327,10 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid, childobject.objectId = relationId; childobject.objectSubId = 0; - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + if (!child_is_partition) + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + else + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); /* * Post creation hook of this inheritance. Since object_access_hook @@ -10749,7 +10757,9 @@ CreateInheritance(Relation child_rel, Relation parent_rel) StoreCatalogInheritance1(RelationGetRelid(child_rel), RelationGetRelid(parent_rel), inhseqno + 1, - catalogRelation); + catalogRelation, + parent_rel->rd_rel->relkind == + RELKIND_PARTITIONED_TABLE); /* Now we're done with pg_inherits */ heap_close(catalogRelation, RowExclusiveLock); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index b0e80a7788..0d1554a73e 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3334,10 +3334,8 @@ ALTER TABLE list_parted2 DROP COLUMN b; ERROR: cannot drop column named in partition key ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; ERROR: cannot alter type of column named in partition key --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int, a int not null) partition by range (b); @@ -3366,5 +3364,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); ERROR: partition constraint is violated by some row --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index fc92cd92dd..bfad755e32 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -659,10 +659,5 @@ Check constraints: "check_a" CHECK (length(a) > 0) Number of partitions: 3 (Use \d+ to list them.) --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index a8c8b28a75..623aa1db93 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1844,22 +1844,4 @@ explain (costs off) select * from range_list_parted where a >= 30; (11 rows) drop table list_parted cascade; -NOTICE: drop cascades to 3 other objects -DETAIL: drop cascades to table part_ab_cd -drop cascades to table part_ef_gh -drop cascades to table part_null_xy drop table range_list_parted cascade; -NOTICE: drop cascades to 13 other objects -DETAIL: drop cascades to table part_1_10 -drop cascades to table part_1_10_ab -drop cascades to table part_1_10_cd -drop cascades to table part_10_20 -drop cascades to table part_10_20_ab -drop cascades to table part_10_20_cd -drop cascades to table part_21_30 -drop cascades to table part_21_30_ab -drop cascades to table part_21_30_cd -drop cascades to table part_40_inf -drop cascades to table part_40_inf_ab -drop cascades to table part_40_inf_cd -drop cascades to table part_40_inf_null diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index 81af3ef497..31cfa4e76e 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -314,10 +314,7 @@ select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_p (9 rows) -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int not null, a int not null) partition by range ((b+0)); @@ -387,4 +384,4 @@ with ins (a, b, c) as (5 rows) -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index a1e9255450..af0d5bfffe 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -220,8 +220,3 @@ DETAIL: Failing row contains (b, 9). update range_parted set b = b + 1 where b = 10; -- cleanup drop table range_parted cascade; -NOTICE: drop cascades to 4 other objects -DETAIL: drop cascades to table part_a_1_a_10 -drop cascades to table part_a_10_a_20 -drop cascades to table part_b_1_b_10 -drop cascades to table part_b_10_b_20 diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 7513769359..0787e785ce 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2194,10 +2194,8 @@ ALTER TABLE part_2 INHERIT inh_test; ALTER TABLE list_parted2 DROP COLUMN b; ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -2222,5 +2220,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index 5f25c436ee..553c084a10 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -593,10 +593,5 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); -- returned. \d parted --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 454e1ce2e7..dfdc24eba8 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -186,10 +186,7 @@ insert into list_parted (b) values (1); select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -241,4 +238,4 @@ with ins (a, b, c) as select a, b, min(c), max(c) from ins group by a, b order by 1; -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; -- 2.11.0 --------------5730E3B4E532BCB0A73A0493 Content-Type: text/plain Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers --------------5730E3B4E532BCB0A73A0493-- ^ permalink raw reply [nested|flat] 7+ messages in thread
* [PATCH 1/2] Allow dropping partitioned table without CASCADE @ 2017-02-16 06:56 amit <amitlangote09@gmail.com> 0 siblings, 0 replies; 7+ messages in thread From: amit @ 2017-02-16 06:56 UTC (permalink / raw) Currently, a normal dependency is created between a inheritance parent and child when creating the child. That means one must specify CASCADE to drop the parent table if a child table exists. When creating partitions as inheritance children, create auto dependency instead, so that partitions are dropped automatically when the parent is dropped i.e., without specifying CASCADE. --- src/backend/commands/tablecmds.c | 26 ++++++++++++++++++-------- src/test/regress/expected/alter_table.out | 10 ++++------ src/test/regress/expected/create_table.out | 9 ++------- src/test/regress/expected/inherit.out | 22 ++-------------------- src/test/regress/expected/insert.out | 7 ++----- src/test/regress/expected/update.out | 7 +------ src/test/regress/sql/alter_table.sql | 10 ++++------ src/test/regress/sql/create_table.sql | 9 ++------- src/test/regress/sql/inherit.sql | 4 ++-- src/test/regress/sql/insert.sql | 7 ++----- src/test/regress/sql/update.sql | 2 +- 11 files changed, 40 insertions(+), 73 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3cea220421..31b50ad77f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -289,9 +289,11 @@ static List *MergeAttributes(List *schema, List *supers, char relpersistence, static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); -static void StoreCatalogInheritance(Oid relationId, List *supers); +static void StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition); static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation); + int16 seqNumber, Relation inhRelation, + bool child_is_partition); static int findAttrByName(const char *attributeName, List *schema); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved); @@ -725,7 +727,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, typaddress); /* Store inheritance information for new rel. */ - StoreCatalogInheritance(relationId, inheritOids); + StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); /* * We must bump the command counter to make the newly-created relation @@ -2240,7 +2242,8 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr) * supers is a list of the OIDs of the new relation's direct ancestors. */ static void -StoreCatalogInheritance(Oid relationId, List *supers) +StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition) { Relation relation; int16 seqNumber; @@ -2270,7 +2273,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) { Oid parentOid = lfirst_oid(entry); - StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation); + StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation, + child_is_partition); seqNumber++; } @@ -2283,7 +2287,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) */ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation) + int16 seqNumber, Relation inhRelation, + bool child_is_partition) { TupleDesc desc = RelationGetDescr(inhRelation); Datum values[Natts_pg_inherits]; @@ -2317,7 +2322,10 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid, childobject.objectId = relationId; childobject.objectSubId = 0; - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + if (!child_is_partition) + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + else + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); /* * Post creation hook of this inheritance. Since object_access_hook @@ -10744,7 +10752,9 @@ CreateInheritance(Relation child_rel, Relation parent_rel) StoreCatalogInheritance1(RelationGetRelid(child_rel), RelationGetRelid(parent_rel), inhseqno + 1, - catalogRelation); + catalogRelation, + parent_rel->rd_rel->relkind == + RELKIND_PARTITIONED_TABLE); /* Now we're done with pg_inherits */ heap_close(catalogRelation, RowExclusiveLock); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index e84af67fb2..ca66158ee3 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3339,10 +3339,8 @@ ALTER TABLE list_parted2 DROP COLUMN b; ERROR: cannot drop column named in partition key ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; ERROR: cannot alter type of column named in partition key --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int, a int not null) partition by range (b); @@ -3371,5 +3369,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); ERROR: partition constraint is violated by some row --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 20eb3d35f9..c07a474b3d 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -667,10 +667,5 @@ Check constraints: "check_a" CHECK (length(a) > 0) Number of partitions: 3 (Use \d+ to list them.) --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index a8c8b28a75..795d9f575c 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1843,23 +1843,5 @@ explain (costs off) select * from range_list_parted where a >= 30; Filter: (a >= 30) (11 rows) -drop table list_parted cascade; -NOTICE: drop cascades to 3 other objects -DETAIL: drop cascades to table part_ab_cd -drop cascades to table part_ef_gh -drop cascades to table part_null_xy -drop table range_list_parted cascade; -NOTICE: drop cascades to 13 other objects -DETAIL: drop cascades to table part_1_10 -drop cascades to table part_1_10_ab -drop cascades to table part_1_10_cd -drop cascades to table part_10_20 -drop cascades to table part_10_20_ab -drop cascades to table part_10_20_cd -drop cascades to table part_21_30 -drop cascades to table part_21_30_ab -drop cascades to table part_21_30_cd -drop cascades to table part_40_inf -drop cascades to table part_40_inf_ab -drop cascades to table part_40_inf_cd -drop cascades to table part_40_inf_null +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index 81af3ef497..31cfa4e76e 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -314,10 +314,7 @@ select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_p (9 rows) -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int not null, a int not null) partition by range ((b+0)); @@ -387,4 +384,4 @@ with ins (a, b, c) as (5 rows) -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index a1e9255450..9366f04255 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -219,9 +219,4 @@ DETAIL: Failing row contains (b, 9). -- ok update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; -NOTICE: drop cascades to 4 other objects -DETAIL: drop cascades to table part_a_1_a_10 -drop cascades to table part_a_10_a_20 -drop cascades to table part_b_1_b_10 -drop cascades to table part_b_10_b_20 +drop table range_parted; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index a403fd8cb4..fbcc739f41 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2199,10 +2199,8 @@ ALTER TABLE part_2 INHERIT inh_test; ALTER TABLE list_parted2 DROP COLUMN b; ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -2227,5 +2225,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index f41dd71475..1f0fa8e16d 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -595,10 +595,5 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); -- returned. \d parted --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index a8b7eb1c8d..836ec22c20 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -612,5 +612,5 @@ explain (costs off) select * from range_list_parted where b is null; explain (costs off) select * from range_list_parted where a is not null and a < 67; explain (costs off) select * from range_list_parted where a >= 30; -drop table list_parted cascade; -drop table range_list_parted cascade; +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 454e1ce2e7..dfdc24eba8 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -186,10 +186,7 @@ insert into list_parted (b) values (1); select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -241,4 +238,4 @@ with ins (a, b, c) as select a, b, min(c), max(c) from ins group by a, b order by 1; -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index d7721ed376..663711997b 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -126,4 +126,4 @@ update range_parted set b = b - 1 where b = 10; update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; +drop table range_parted; -- 2.11.0 --------------CE28692440D789D70003F6EB Content-Type: text/x-diff; name="0002-Add-regression-tests-foreign-partition-DDL.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0002-Add-regression-tests-foreign-partition-DDL.patch" ^ permalink raw reply [nested|flat] 7+ messages in thread
* [PATCH] Allow dropping partitioned table without CASCADE @ 2017-02-16 06:56 amit <amitlangote09@gmail.com> 0 siblings, 0 replies; 7+ messages in thread From: amit @ 2017-02-16 06:56 UTC (permalink / raw) Currently, a normal dependency is created between a inheritance parent and child when creating the child. That means one must specify CASCADE to drop the parent table if a child table exists. When creating partitions as inheritance children, create auto dependency instead, so that partitions are dropped automatically when the parent is dropped i.e., without specifying CASCADE. --- src/backend/commands/tablecmds.c | 26 ++++++++++++++++++-------- src/test/regress/expected/alter_table.out | 10 ++++------ src/test/regress/expected/create_table.out | 9 ++------- src/test/regress/expected/inherit.out | 22 ++-------------------- src/test/regress/expected/insert.out | 7 ++----- src/test/regress/expected/update.out | 7 +------ src/test/regress/sql/alter_table.sql | 10 ++++------ src/test/regress/sql/create_table.sql | 9 ++------- src/test/regress/sql/inherit.sql | 4 ++-- src/test/regress/sql/insert.sql | 7 ++----- src/test/regress/sql/update.sql | 2 +- 11 files changed, 40 insertions(+), 73 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3cea220421..cf566f974b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -289,9 +289,11 @@ static List *MergeAttributes(List *schema, List *supers, char relpersistence, static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); -static void StoreCatalogInheritance(Oid relationId, List *supers); +static void StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition); static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation); + int16 seqNumber, Relation inhRelation, + bool child_is_partition); static int findAttrByName(const char *attributeName, List *schema); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved); @@ -725,7 +727,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, typaddress); /* Store inheritance information for new rel. */ - StoreCatalogInheritance(relationId, inheritOids); + StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); /* * We must bump the command counter to make the newly-created relation @@ -2240,7 +2242,8 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr) * supers is a list of the OIDs of the new relation's direct ancestors. */ static void -StoreCatalogInheritance(Oid relationId, List *supers) +StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition) { Relation relation; int16 seqNumber; @@ -2270,7 +2273,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) { Oid parentOid = lfirst_oid(entry); - StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation); + StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation, + child_is_partition); seqNumber++; } @@ -2283,7 +2287,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) */ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation) + int16 seqNumber, Relation inhRelation, + bool child_is_partition) { TupleDesc desc = RelationGetDescr(inhRelation); Datum values[Natts_pg_inherits]; @@ -2317,7 +2322,10 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid, childobject.objectId = relationId; childobject.objectSubId = 0; - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + if (child_is_partition) + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); + else + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); /* * Post creation hook of this inheritance. Since object_access_hook @@ -10744,7 +10752,9 @@ CreateInheritance(Relation child_rel, Relation parent_rel) StoreCatalogInheritance1(RelationGetRelid(child_rel), RelationGetRelid(parent_rel), inhseqno + 1, - catalogRelation); + catalogRelation, + parent_rel->rd_rel->relkind == + RELKIND_PARTITIONED_TABLE); /* Now we're done with pg_inherits */ heap_close(catalogRelation, RowExclusiveLock); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 9885fcba89..c15bbdcbd1 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3339,10 +3339,8 @@ ALTER TABLE list_parted2 DROP COLUMN b; ERROR: cannot drop column named in partition key ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; ERROR: cannot alter type of column named in partition key --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int, a int not null) partition by range (b); @@ -3371,5 +3369,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); ERROR: partition constraint is violated by some row --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 20eb3d35f9..c07a474b3d 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -667,10 +667,5 @@ Check constraints: "check_a" CHECK (length(a) > 0) Number of partitions: 3 (Use \d+ to list them.) --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index a8c8b28a75..795d9f575c 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1843,23 +1843,5 @@ explain (costs off) select * from range_list_parted where a >= 30; Filter: (a >= 30) (11 rows) -drop table list_parted cascade; -NOTICE: drop cascades to 3 other objects -DETAIL: drop cascades to table part_ab_cd -drop cascades to table part_ef_gh -drop cascades to table part_null_xy -drop table range_list_parted cascade; -NOTICE: drop cascades to 13 other objects -DETAIL: drop cascades to table part_1_10 -drop cascades to table part_1_10_ab -drop cascades to table part_1_10_cd -drop cascades to table part_10_20 -drop cascades to table part_10_20_ab -drop cascades to table part_10_20_cd -drop cascades to table part_21_30 -drop cascades to table part_21_30_ab -drop cascades to table part_21_30_cd -drop cascades to table part_40_inf -drop cascades to table part_40_inf_ab -drop cascades to table part_40_inf_cd -drop cascades to table part_40_inf_null +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index 81af3ef497..31cfa4e76e 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -314,10 +314,7 @@ select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_p (9 rows) -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int not null, a int not null) partition by range ((b+0)); @@ -387,4 +384,4 @@ with ins (a, b, c) as (5 rows) -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index a1e9255450..9366f04255 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -219,9 +219,4 @@ DETAIL: Failing row contains (b, 9). -- ok update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; -NOTICE: drop cascades to 4 other objects -DETAIL: drop cascades to table part_a_1_a_10 -drop cascades to table part_a_10_a_20 -drop cascades to table part_b_1_b_10 -drop cascades to table part_b_10_b_20 +drop table range_parted; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index f7b754f0be..37f327bf6d 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2199,10 +2199,8 @@ ALTER TABLE part_2 INHERIT inh_test; ALTER TABLE list_parted2 DROP COLUMN b; ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -2227,5 +2225,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index f41dd71475..1f0fa8e16d 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -595,10 +595,5 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); -- returned. \d parted --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index a8b7eb1c8d..836ec22c20 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -612,5 +612,5 @@ explain (costs off) select * from range_list_parted where b is null; explain (costs off) select * from range_list_parted where a is not null and a < 67; explain (costs off) select * from range_list_parted where a >= 30; -drop table list_parted cascade; -drop table range_list_parted cascade; +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 454e1ce2e7..dfdc24eba8 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -186,10 +186,7 @@ insert into list_parted (b) values (1); select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -241,4 +238,4 @@ with ins (a, b, c) as select a, b, min(c), max(c) from ins group by a, b order by 1; -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index d7721ed376..663711997b 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -126,4 +126,4 @@ update range_parted set b = b - 1 where b = 10; update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; +drop table range_parted; -- 2.11.0 --------------45F030A7BE1F47DD3B7363A6 Content-Type: text/plain Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers --------------45F030A7BE1F47DD3B7363A6-- ^ permalink raw reply [nested|flat] 7+ messages in thread
* [PATCH] Allow dropping partitioned table without CASCADE @ 2017-02-16 06:56 amit <amitlangote09@gmail.com> 0 siblings, 0 replies; 7+ messages in thread From: amit @ 2017-02-16 06:56 UTC (permalink / raw) Currently, a normal dependency is created between a inheritance parent and child when creating the child. That means one must specify CASCADE to drop the parent table if a child table exists. When creating partitions as inheritance children, create auto dependency instead, so that partitions are dropped automatically when the parent is dropped i.e., without specifying CASCADE. --- src/backend/commands/tablecmds.c | 26 ++++++++++++++++++-------- src/test/regress/expected/alter_table.out | 10 ++++------ src/test/regress/expected/create_table.out | 9 ++------- src/test/regress/expected/inherit.out | 22 ++-------------------- src/test/regress/expected/insert.out | 7 ++----- src/test/regress/expected/update.out | 7 +------ src/test/regress/sql/alter_table.sql | 10 ++++------ src/test/regress/sql/create_table.sql | 9 ++------- src/test/regress/sql/inherit.sql | 4 ++-- src/test/regress/sql/insert.sql | 7 ++----- src/test/regress/sql/update.sql | 2 +- 11 files changed, 40 insertions(+), 73 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3cea220421..31b50ad77f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -289,9 +289,11 @@ static List *MergeAttributes(List *schema, List *supers, char relpersistence, static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); -static void StoreCatalogInheritance(Oid relationId, List *supers); +static void StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition); static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation); + int16 seqNumber, Relation inhRelation, + bool child_is_partition); static int findAttrByName(const char *attributeName, List *schema); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved); @@ -725,7 +727,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, typaddress); /* Store inheritance information for new rel. */ - StoreCatalogInheritance(relationId, inheritOids); + StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); /* * We must bump the command counter to make the newly-created relation @@ -2240,7 +2242,8 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr) * supers is a list of the OIDs of the new relation's direct ancestors. */ static void -StoreCatalogInheritance(Oid relationId, List *supers) +StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition) { Relation relation; int16 seqNumber; @@ -2270,7 +2273,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) { Oid parentOid = lfirst_oid(entry); - StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation); + StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation, + child_is_partition); seqNumber++; } @@ -2283,7 +2287,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) */ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation) + int16 seqNumber, Relation inhRelation, + bool child_is_partition) { TupleDesc desc = RelationGetDescr(inhRelation); Datum values[Natts_pg_inherits]; @@ -2317,7 +2322,10 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid, childobject.objectId = relationId; childobject.objectSubId = 0; - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + if (!child_is_partition) + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + else + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); /* * Post creation hook of this inheritance. Since object_access_hook @@ -10744,7 +10752,9 @@ CreateInheritance(Relation child_rel, Relation parent_rel) StoreCatalogInheritance1(RelationGetRelid(child_rel), RelationGetRelid(parent_rel), inhseqno + 1, - catalogRelation); + catalogRelation, + parent_rel->rd_rel->relkind == + RELKIND_PARTITIONED_TABLE); /* Now we're done with pg_inherits */ heap_close(catalogRelation, RowExclusiveLock); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 9885fcba89..c15bbdcbd1 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3339,10 +3339,8 @@ ALTER TABLE list_parted2 DROP COLUMN b; ERROR: cannot drop column named in partition key ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; ERROR: cannot alter type of column named in partition key --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int, a int not null) partition by range (b); @@ -3371,5 +3369,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); ERROR: partition constraint is violated by some row --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 20eb3d35f9..c07a474b3d 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -667,10 +667,5 @@ Check constraints: "check_a" CHECK (length(a) > 0) Number of partitions: 3 (Use \d+ to list them.) --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index a8c8b28a75..795d9f575c 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1843,23 +1843,5 @@ explain (costs off) select * from range_list_parted where a >= 30; Filter: (a >= 30) (11 rows) -drop table list_parted cascade; -NOTICE: drop cascades to 3 other objects -DETAIL: drop cascades to table part_ab_cd -drop cascades to table part_ef_gh -drop cascades to table part_null_xy -drop table range_list_parted cascade; -NOTICE: drop cascades to 13 other objects -DETAIL: drop cascades to table part_1_10 -drop cascades to table part_1_10_ab -drop cascades to table part_1_10_cd -drop cascades to table part_10_20 -drop cascades to table part_10_20_ab -drop cascades to table part_10_20_cd -drop cascades to table part_21_30 -drop cascades to table part_21_30_ab -drop cascades to table part_21_30_cd -drop cascades to table part_40_inf -drop cascades to table part_40_inf_ab -drop cascades to table part_40_inf_cd -drop cascades to table part_40_inf_null +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index 81af3ef497..31cfa4e76e 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -314,10 +314,7 @@ select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_p (9 rows) -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int not null, a int not null) partition by range ((b+0)); @@ -387,4 +384,4 @@ with ins (a, b, c) as (5 rows) -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index a1e9255450..9366f04255 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -219,9 +219,4 @@ DETAIL: Failing row contains (b, 9). -- ok update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; -NOTICE: drop cascades to 4 other objects -DETAIL: drop cascades to table part_a_1_a_10 -drop cascades to table part_a_10_a_20 -drop cascades to table part_b_1_b_10 -drop cascades to table part_b_10_b_20 +drop table range_parted; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index f7b754f0be..37f327bf6d 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2199,10 +2199,8 @@ ALTER TABLE part_2 INHERIT inh_test; ALTER TABLE list_parted2 DROP COLUMN b; ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -2227,5 +2225,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index f41dd71475..1f0fa8e16d 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -595,10 +595,5 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); -- returned. \d parted --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index a8b7eb1c8d..836ec22c20 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -612,5 +612,5 @@ explain (costs off) select * from range_list_parted where b is null; explain (costs off) select * from range_list_parted where a is not null and a < 67; explain (costs off) select * from range_list_parted where a >= 30; -drop table list_parted cascade; -drop table range_list_parted cascade; +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 454e1ce2e7..dfdc24eba8 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -186,10 +186,7 @@ insert into list_parted (b) values (1); select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -241,4 +238,4 @@ with ins (a, b, c) as select a, b, min(c), max(c) from ins group by a, b order by 1; -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index d7721ed376..663711997b 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -126,4 +126,4 @@ update range_parted set b = b - 1 where b = 10; update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; +drop table range_parted; -- 2.11.0 --------------655E53A440FB4B4ADAF5161F Content-Type: text/plain Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers --------------655E53A440FB4B4ADAF5161F-- ^ permalink raw reply [nested|flat] 7+ messages in thread
* [PATCH] Allow dropping partitioned table without CASCADE @ 2017-02-16 06:56 amit <amitlangote09@gmail.com> 0 siblings, 0 replies; 7+ messages in thread From: amit @ 2017-02-16 06:56 UTC (permalink / raw) Currently, a normal dependency is created between a inheritance parent and child when creating the child. That means one must specify CASCADE to drop the parent table if a child table exists. When creating partitions as inheritance children, create auto dependency instead, so that partitions are dropped automatically when the parent is dropped i.e., without specifying CASCADE. --- src/backend/commands/tablecmds.c | 26 ++++++++++++++++++-------- src/test/regress/expected/alter_table.out | 10 ++++------ src/test/regress/expected/create_table.out | 9 ++------- src/test/regress/expected/inherit.out | 22 ++-------------------- src/test/regress/expected/insert.out | 7 ++----- src/test/regress/expected/update.out | 7 +------ src/test/regress/sql/alter_table.sql | 10 ++++------ src/test/regress/sql/create_table.sql | 9 ++------- src/test/regress/sql/inherit.sql | 4 ++-- src/test/regress/sql/insert.sql | 7 ++----- src/test/regress/sql/update.sql | 2 +- 11 files changed, 40 insertions(+), 73 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3cea220421..cf566f974b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -289,9 +289,11 @@ static List *MergeAttributes(List *schema, List *supers, char relpersistence, static bool MergeCheckConstraint(List *constraints, char *name, Node *expr); static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel); static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel); -static void StoreCatalogInheritance(Oid relationId, List *supers); +static void StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition); static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation); + int16 seqNumber, Relation inhRelation, + bool child_is_partition); static int findAttrByName(const char *attributeName, List *schema); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid, ObjectAddresses *objsMoved); @@ -725,7 +727,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, typaddress); /* Store inheritance information for new rel. */ - StoreCatalogInheritance(relationId, inheritOids); + StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); /* * We must bump the command counter to make the newly-created relation @@ -2240,7 +2242,8 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr) * supers is a list of the OIDs of the new relation's direct ancestors. */ static void -StoreCatalogInheritance(Oid relationId, List *supers) +StoreCatalogInheritance(Oid relationId, List *supers, + bool child_is_partition) { Relation relation; int16 seqNumber; @@ -2270,7 +2273,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) { Oid parentOid = lfirst_oid(entry); - StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation); + StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation, + child_is_partition); seqNumber++; } @@ -2283,7 +2287,8 @@ StoreCatalogInheritance(Oid relationId, List *supers) */ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid, - int16 seqNumber, Relation inhRelation) + int16 seqNumber, Relation inhRelation, + bool child_is_partition) { TupleDesc desc = RelationGetDescr(inhRelation); Datum values[Natts_pg_inherits]; @@ -2317,7 +2322,10 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid, childobject.objectId = relationId; childobject.objectSubId = 0; - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + if (child_is_partition) + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); + else + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); /* * Post creation hook of this inheritance. Since object_access_hook @@ -10744,7 +10752,9 @@ CreateInheritance(Relation child_rel, Relation parent_rel) StoreCatalogInheritance1(RelationGetRelid(child_rel), RelationGetRelid(parent_rel), inhseqno + 1, - catalogRelation); + catalogRelation, + parent_rel->rd_rel->relkind == + RELKIND_PARTITIONED_TABLE); /* Now we're done with pg_inherits */ heap_close(catalogRelation, RowExclusiveLock); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 9885fcba89..c15bbdcbd1 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3339,10 +3339,8 @@ ALTER TABLE list_parted2 DROP COLUMN b; ERROR: cannot drop column named in partition key ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; ERROR: cannot alter type of column named in partition key --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int, a int not null) partition by range (b); @@ -3371,5 +3369,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); ERROR: partition constraint is violated by some row --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index 20eb3d35f9..c07a474b3d 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -667,10 +667,5 @@ Check constraints: "check_a" CHECK (length(a) > 0) Number of partitions: 3 (Use \d+ to list them.) --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index a8c8b28a75..795d9f575c 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -1843,23 +1843,5 @@ explain (costs off) select * from range_list_parted where a >= 30; Filter: (a >= 30) (11 rows) -drop table list_parted cascade; -NOTICE: drop cascades to 3 other objects -DETAIL: drop cascades to table part_ab_cd -drop cascades to table part_ef_gh -drop cascades to table part_null_xy -drop table range_list_parted cascade; -NOTICE: drop cascades to 13 other objects -DETAIL: drop cascades to table part_1_10 -drop cascades to table part_1_10_ab -drop cascades to table part_1_10_cd -drop cascades to table part_10_20 -drop cascades to table part_10_20_ab -drop cascades to table part_10_20_cd -drop cascades to table part_21_30 -drop cascades to table part_21_30_ab -drop cascades to table part_21_30_cd -drop cascades to table part_40_inf -drop cascades to table part_40_inf_ab -drop cascades to table part_40_inf_cd -drop cascades to table part_40_inf_null +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out index 81af3ef497..31cfa4e76e 100644 --- a/src/test/regress/expected/insert.out +++ b/src/test/regress/expected/insert.out @@ -314,10 +314,7 @@ select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_p (9 rows) -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); create table p1 (b int not null, a int not null) partition by range ((b+0)); @@ -387,4 +384,4 @@ with ins (a, b, c) as (5 rows) -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index a1e9255450..9366f04255 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -219,9 +219,4 @@ DETAIL: Failing row contains (b, 9). -- ok update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; -NOTICE: drop cascades to 4 other objects -DETAIL: drop cascades to table part_a_1_a_10 -drop cascades to table part_a_10_a_20 -drop cascades to table part_b_1_b_10 -drop cascades to table part_b_10_b_20 +drop table range_parted; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index f7b754f0be..37f327bf6d 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2199,10 +2199,8 @@ ALTER TABLE part_2 INHERIT inh_test; ALTER TABLE list_parted2 DROP COLUMN b; ALTER TABLE list_parted2 ALTER COLUMN b TYPE text; --- cleanup: avoid using CASCADE -DROP TABLE list_parted, part_1; -DROP TABLE list_parted2, part_2, part_5, part_5_a; -DROP TABLE range_parted, part1, part2; +-- cleanup +DROP TABLE list_parted, list_parted2, range_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -2227,5 +2225,5 @@ insert into p1 (a, b) values (2, 3); -- check that partition validation scan correctly detects violating rows alter table p attach partition p1 for values from (1, 2) to (1, 10); --- cleanup: avoid using CASCADE -drop table p, p1, p11; +-- cleanup +drop table p; diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql index f41dd71475..1f0fa8e16d 100644 --- a/src/test/regress/sql/create_table.sql +++ b/src/test/regress/sql/create_table.sql @@ -595,10 +595,5 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10); -- returned. \d parted --- cleanup: avoid using CASCADE -DROP TABLE parted, part_a, part_b, part_c, part_c_1_10; -DROP TABLE list_parted, part_1, part_2, part_null; -DROP TABLE range_parted; -DROP TABLE list_parted2, part_ab, part_null_z; -DROP TABLE range_parted2, part0, part1, part2, part3; -DROP TABLE range_parted3, part00, part10, part11, part12; +-- cleanup +DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3; diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index a8b7eb1c8d..836ec22c20 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -612,5 +612,5 @@ explain (costs off) select * from range_list_parted where b is null; explain (costs off) select * from range_list_parted where a is not null and a < 67; explain (costs off) select * from range_list_parted where a >= 30; -drop table list_parted cascade; -drop table range_list_parted cascade; +drop table list_parted; +drop table range_list_parted; diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql index 454e1ce2e7..dfdc24eba8 100644 --- a/src/test/regress/sql/insert.sql +++ b/src/test/regress/sql/insert.sql @@ -186,10 +186,7 @@ insert into list_parted (b) values (1); select tableoid::regclass::text, a, min(b) as min_b, max(b) as max_b from list_parted group by 1, 2 order by 1; -- cleanup -drop table part1, part2, part3, part4, range_parted; -drop table part_ee_ff3_1, part_ee_ff3_2, part_ee_ff1, part_ee_ff2, part_ee_ff3; -drop table part_ee_ff, part_gg2_2, part_gg2_1, part_gg2, part_gg1, part_gg; -drop table part_aa_bb, part_cc_dd, part_null, list_parted; +drop table range_parted, list_parted; -- more tests for certain multi-level partitioning scenarios create table p (a int, b int) partition by range (a, b); @@ -241,4 +238,4 @@ with ins (a, b, c) as select a, b, min(c), max(c) from ins group by a, b order by 1; -- cleanup -drop table p, p1, p11, p12, p2, p3, p4; +drop table p; diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index d7721ed376..663711997b 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -126,4 +126,4 @@ update range_parted set b = b - 1 where b = 10; update range_parted set b = b + 1 where b = 10; -- cleanup -drop table range_parted cascade; +drop table range_parted; -- 2.11.0 --------------EB312FBA713FE247EB63323E Content-Type: text/plain Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers --------------EB312FBA713FE247EB63323E-- ^ permalink raw reply [nested|flat] 7+ messages in thread
* [PATCH v56 1/3] Allow logical replication snapshots to be database-specific @ 2026-04-06 22:07 Álvaro Herrera <alvherre@kurilemu.de> 0 siblings, 0 replies; 7+ messages in thread From: Álvaro Herrera @ 2026-04-06 22:07 UTC (permalink / raw) By default, the logical decoding assumes access to shared catalogs, so the snapshot builder needs to consider cluster-wide XIDs during startup. That in turn means that, if any transaction is already running (and has XID assigned), the snapshot builder needs to wait for its completion, as it does not know if that transaction performed catalog changes earlier. A possible problem with this concept is that if REPACK (CONCURRENTLY) is running in some database, backends running the same command in other databases get stuck until the first one has committed. Thus only a single backend in the cluster can run REPACK (CONCURRENTLY) at any time. Likewise, REPACK (CONCURRENTLY) can block walsenders starting on behalf of subscriptions throughout the cluster. This patch adds a new option to logical replication output plugin, to declare that it does not use shared catalogs (i.e. catalogs that can be changed by transactions running in other databases in the cluster). In that case, no snapshot the backend will use during the decoding needs to contain information about transactions running in other databases. Thus the snapshot builder only needs to wait for completion of transactions in the current database. Currently we only use this option in the REPACK background worker. It could possibly be used in the plugin for logical replication too, however that would need thorough analysis of that plugin. Bump WAL version number, due to a new field in xl_running_xacts. Author: Antonin Houska <ah@cybertec.at> Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de> Discussion: https://postgr.es/m/90475.1775218118@localhost --- contrib/pg_visibility/pg_visibility.c | 4 +- doc/src/sgml/logicaldecoding.sgml | 4 ++ src/backend/access/index/genam.c | 8 +++ src/backend/access/rmgrdesc/standbydesc.c | 2 + src/backend/access/transam/xlog.c | 2 +- src/backend/access/transam/xlogfuncs.c | 2 +- src/backend/postmaster/bgwriter.c | 2 +- src/backend/replication/logical/decode.c | 17 +++++- src/backend/replication/logical/logical.c | 3 + src/backend/replication/logical/snapbuild.c | 63 ++++++++++++++++++++- src/backend/replication/pgrepack/pgrepack.c | 7 +++ src/backend/replication/slot.c | 2 +- src/backend/storage/ipc/procarray.c | 23 +++++++- src/backend/storage/ipc/standby.c | 24 +++++++- src/include/access/genam.h | 1 + src/include/access/xlog_internal.h | 2 +- src/include/miscadmin.h | 9 +++ src/include/replication/output_plugin.h | 1 + src/include/replication/snapbuild.h | 3 +- src/include/storage/procarray.h | 2 +- src/include/storage/standby.h | 3 +- src/include/storage/standbydefs.h | 1 + 22 files changed, 167 insertions(+), 18 deletions(-) diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index dfab0b64cf5..d564bd2a00c 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -621,7 +621,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel) else if (rel == NULL || rel->rd_rel->relisshared) { /* Shared relation: take into account all running xids */ - runningTransactions = GetRunningTransactionData(); + runningTransactions = GetRunningTransactionData(InvalidOid); LWLockRelease(ProcArrayLock); LWLockRelease(XidGenLock); return runningTransactions->oldestRunningXid; @@ -632,7 +632,7 @@ GetStrictOldestNonRemovableTransactionId(Relation rel) * Normal relation: take into account xids running within the current * database */ - runningTransactions = GetRunningTransactionData(); + runningTransactions = GetRunningTransactionData(InvalidOid); LWLockRelease(ProcArrayLock); LWLockRelease(XidGenLock); return runningTransactions->oldestDatabaseRunningXid; diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml index 6dc49108997..9b1d68d0de6 100644 --- a/doc/src/sgml/logicaldecoding.sgml +++ b/doc/src/sgml/logicaldecoding.sgml @@ -959,6 +959,7 @@ typedef struct OutputPluginOptions { OutputPluginOutputType output_type; bool receive_rewrites; + bool need_shared_catalogs; } OutputPluginOptions; </programlisting> <literal>output_type</literal> has to either be set to @@ -969,6 +970,9 @@ typedef struct OutputPluginOptions also be called for changes made by heap rewrites during certain DDL operations. These are of interest to plugins that handle DDL replication, but they require special handling. + <literal>need_shared_catalogs</literal> can be set to false if you are + certain the plugin functions do not access shared system catalogs. + Doing so can speed up creation of replication slots that use this plugin. </para> <para> diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index 1408989c568..97d44b84622 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -394,6 +394,14 @@ systable_beginscan(Relation heapRelation, SysScanDesc sysscan; Relation irel; + /* + * If this backend promised that it won't access shared catalogs during + * logical decoding, this it the right place to verify. + */ + Assert(!HistoricSnapshotActive() || + accessSharedCatalogsInDecoding || + !heapRelation->rd_rel->relisshared); + if (indexOK && !IgnoreSystemIndexes && !ReindexIsProcessingIndex(indexId)) diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c index 0a291354ae2..685d1bdb024 100644 --- a/src/backend/access/rmgrdesc/standbydesc.c +++ b/src/backend/access/rmgrdesc/standbydesc.c @@ -41,6 +41,8 @@ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec) for (i = 0; i < xlrec->subxcnt; i++) appendStringInfo(buf, " %u", xlrec->xids[xlrec->xcnt + i]); } + + appendStringInfo(buf, "; dbid: %u", xlrec->dbid); } void diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b82af9a85c0..3f08a832ca6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7735,7 +7735,7 @@ CreateCheckPoint(int flags) * recovery we don't need to write running xact data. */ if (!shutdown && XLogStandbyInfoActive()) - LogStandbySnapshot(); + LogStandbySnapshot(InvalidOid); START_CRIT_SECTION(); diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 65bbaeda59c..0f5979691e6 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -245,7 +245,7 @@ pg_log_standby_snapshot(PG_FUNCTION_ARGS) (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("pg_log_standby_snapshot() can only be used if \"wal_level\" >= \"replica\""))); - recptr = LogStandbySnapshot(); + recptr = LogStandbySnapshot(InvalidOid); /* * As a convenience, return the WAL location of the last inserted record diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 1d8947774a9..a30de4262eb 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -289,7 +289,7 @@ BackgroundWriterMain(const void *startup_data, size_t startup_data_len) if (now >= timeout && last_snapshot_lsn <= GetLastImportantRecPtr()) { - last_snapshot_lsn = LogStandbySnapshot(); + last_snapshot_lsn = LogStandbySnapshot(InvalidOid); last_snapshot_ts = now; } } diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c index c9fea8cad28..38c5a4f5540 100644 --- a/src/backend/replication/logical/decode.c +++ b/src/backend/replication/logical/decode.c @@ -382,7 +382,16 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { xl_running_xacts *running = (xl_running_xacts *) XLogRecGetData(r); - SnapBuildProcessRunningXacts(builder, buf->origptr, running); + /* + * Update this decoder's idea of transactions currently + * running. In doing so we will determine whether we have + * reached consistent status. + * + * If the output plugin doesn't need access to shared + * catalogs, we can ignore transactions in other databases. + */ + SnapBuildProcessRunningXacts(builder, buf->origptr, running, + !ctx->options.need_shared_catalogs); /* * Abort all transactions that we keep track of, that are @@ -392,8 +401,12 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) * all running transactions which includes prepared ones, * while shutdown checkpoints just know that no non-prepared * transactions are in progress. + * + * The database-specific records might work here too, but it's + * not their purpose. */ - ReorderBufferAbortOld(ctx->reorder, running->oldestRunningXid); + if (!OidIsValid(running->dbid)) + ReorderBufferAbortOld(ctx->reorder, running->oldestRunningXid); } break; case XLOG_STANDBY_LOCK: diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index f20d0c542f3..8ceaf64d164 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -285,6 +285,9 @@ StartupDecodingContext(List *output_plugin_options, ctx->write = do_write; ctx->update_progress = update_progress; + /* Assume shared catalog access. The startup callback can change it. */ + ctx->options.need_shared_catalogs = true; + ctx->output_plugin_options = output_plugin_options; ctx->fast_forward = fast_forward; diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index b4269a3b102..ffb4ab2cf2a 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -154,6 +154,14 @@ static ResourceOwner SavedResourceOwnerDuringExport = NULL; static bool ExportInProgress = false; +/* + * If a backend is going to do logical decoding and the output plugin does + * not need to access shared catalogs, setting this variable to false can make + * the decoding startup faster. In particular, the backend will not need to + * wait for completion of already running transactions in other databases. + */ +bool accessSharedCatalogsInDecoding = true; + /* ->committed and ->catchange manipulation */ static void SnapBuildPurgeOlderTxn(SnapBuild *builder); @@ -170,7 +178,8 @@ static inline bool SnapBuildXidHasCatalogChanges(SnapBuild *builder, Transaction uint32 xinfo); /* xlog reading helper functions for SnapBuildProcessRunningXacts */ -static bool SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running); +static bool SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, + xl_running_xacts *running); static void SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff); /* serialization functions */ @@ -226,6 +235,9 @@ AllocateSnapshotBuilder(ReorderBuffer *reorder, MemoryContextSwitchTo(oldcontext); + /* The default is that shared catalog are used. */ + accessSharedCatalogsInDecoding = true; + return builder; } @@ -244,6 +256,9 @@ FreeSnapshotBuilder(SnapBuild *builder) builder->snapshot = NULL; } + /* The default is that shared catalog are used. */ + accessSharedCatalogsInDecoding = true; + /* other resources are deallocated via memory context reset */ MemoryContextDelete(context); } @@ -1136,7 +1151,8 @@ SnapBuildXidHasCatalogChanges(SnapBuild *builder, TransactionId xid, * anymore. */ void -SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running) +SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running, + bool db_specific) { ReorderBufferTXN *txn; TransactionId xmin; @@ -1148,6 +1164,33 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact */ if (builder->state < SNAPBUILD_CONSISTENT) { + /* + * To reduce the potential for unnecessarily waiting for completion of + * unrelated transactions, the caller can declare that only + * transactions of the current database are relevant at this stage. + */ + if (db_specific) + { + /* + * If we must only keep track of transactions running in the + * current database, we need transaction info from exactly that + * database. + */ + if (running->dbid != MyDatabaseId) + { + LogStandbySnapshot(MyDatabaseId); + + return; + } + + /* + * We'd better be able to check during scan if the plugin does not + * lie. + */ + if (accessSharedCatalogsInDecoding) + accessSharedCatalogsInDecoding = false; + } + /* returns false if there's no point in performing cleanup just yet */ if (!SnapBuildFindSnapshot(builder, lsn, running)) return; @@ -1155,6 +1198,16 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact else SnapBuildSerialize(builder, lsn); + /* + * Database specific transaction info may exist to reach CONSISTENT state + * faster, however the code below makes no use of it. Moreover, such + * record might cause problems because the following normal (cluster-wide) + * record can have lower value of oldestRunningXid. In that case, let's + * wait with the cleanup for the next regular cluster-wide record. + */ + if (OidIsValid(running->dbid)) + return; + /* * Update range of interesting xids based on the running xacts * information. We don't increase ->xmax using it, because once we are in @@ -1465,7 +1518,11 @@ SnapBuildWaitSnapshot(xl_running_xacts *running, TransactionId cutoff) */ if (!RecoveryInProgress()) { - LogStandbySnapshot(); + /* + * If the last transaction info was about specific database, so needs + * to be the next one - at least until we're in the CONSISTENT state. + */ + LogStandbySnapshot(running->dbid); } } diff --git a/src/backend/replication/pgrepack/pgrepack.c b/src/backend/replication/pgrepack/pgrepack.c index 457b6518a8e..4da66aa0f44 100644 --- a/src/backend/replication/pgrepack/pgrepack.c +++ b/src/backend/replication/pgrepack/pgrepack.c @@ -52,6 +52,13 @@ repack_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt, /* Probably unnecessary, as we don't use the SQL interface ... */ opt->output_type = OUTPUT_PLUGIN_BINARY_OUTPUT; + /* + * REPACK doesn't need access to shared catalogs, so we can speed up the + * historic snapshot creation by setting this flag. We'll only have to + * wait for transactions in our database. + */ + opt->need_shared_catalogs = false; + if (ctx->output_plugin_options != NIL) { ereport(ERROR, diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 21a213a0ebf..a1f37e59dbc 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -1756,7 +1756,7 @@ ReplicationSlotReserveWal(void) XLogRecPtr flushptr; /* make sure we have enough information to start */ - flushptr = LogStandbySnapshot(); + flushptr = LogStandbySnapshot(InvalidOid); /* and make sure it's fsynced to disk */ XLogFlush(flushptr); diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index f540bb6b23f..9299bcebbda 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -2623,9 +2623,11 @@ ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc) * * Note that if any transaction has overflowed its cached subtransactions * then there is no real need include any subtransactions. + * + * If 'dbid' is valid, only gather transactions running in that database. */ RunningTransactions -GetRunningTransactionData(void) +GetRunningTransactionData(Oid dbid) { /* result workspace */ static RunningTransactionsData CurrentRunningXactsData; @@ -2700,6 +2702,18 @@ GetRunningTransactionData(void) if (!TransactionIdIsValid(xid)) continue; + /* + * Filter by database OID if requested. + */ + if (OidIsValid(dbid)) + { + int pgprocno = arrayP->pgprocnos[index]; + PGPROC *proc = &allProcs[pgprocno]; + + if (proc->databaseId != dbid) + continue; + } + /* * Be careful not to exclude any xids before calculating the values of * oldestRunningXid and suboverflowed, since these are used to clean @@ -2750,6 +2764,12 @@ GetRunningTransactionData(void) PGPROC *proc = &allProcs[pgprocno]; int nsubxids; + /* + * Filter by database OID if requested. + */ + if (OidIsValid(dbid) && proc->databaseId != dbid) + continue; + /* * Save subtransaction XIDs. Other backends can't add or remove * entries while we're holding XidGenLock. @@ -2783,6 +2803,7 @@ GetRunningTransactionData(void) * increases if slots do. */ + CurrentRunningXacts->dbid = dbid; CurrentRunningXacts->xcnt = count - subcount; CurrentRunningXacts->subxcnt = subcount; CurrentRunningXacts->subxid_status = suboverflowed ? SUBXIDS_IN_SUBTRANS : SUBXIDS_IN_ARRAY; diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index de9092fdf5b..29af7733948 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -1188,6 +1188,14 @@ standby_redo(XLogReaderState *record) xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record); RunningTransactionsData running; + /* + * Records issued for specific database are not suitable for physical + * replication because that affects the whole cluster. In particular, + * the list of XID is probably incomplete here. + */ + if (OidIsValid(xlrec->dbid)) + return; + running.xcnt = xlrec->xcnt; running.subxcnt = xlrec->subxcnt; running.subxid_status = xlrec->subxid_overflow ? SUBXIDS_MISSING : SUBXIDS_IN_ARRAY; @@ -1277,11 +1285,22 @@ standby_redo(XLogReaderState *record) * as there's no independent knob to just enable logical decoding. For * details of how this is used, check snapbuild.c's introductory comment. * + * If 'dbid' is valid, only gather transactions running in that + * database. snapbuild.c can use such running xacts information for faster + * startup, but it still needs normal (cluster-wide) during the actual + * decoding - see standby_decode() and SnapBuildProcessRunningXacts() for + * details. Other processes (e.g. checkpointer) issue the cluster-wide records + * whether logical decoding is active or not. + * + * Please be careful about using this argument for other purposes. In + * particular, physical replication *must* ignore the database-specific + * records, exactly because they do not cover the whole cluster - see + * standby_redo(). * * Returns the RecPtr of the last inserted record. */ XLogRecPtr -LogStandbySnapshot(void) +LogStandbySnapshot(Oid dbid) { XLogRecPtr recptr; RunningTransactions running; @@ -1314,7 +1333,7 @@ LogStandbySnapshot(void) * Log details of all in-progress transactions. This should be the last * record we write, because standby will open up when it sees this. */ - running = GetRunningTransactionData(); + running = GetRunningTransactionData(dbid); /* * GetRunningTransactionData() acquired ProcArrayLock, we must release it. @@ -1358,6 +1377,7 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts) xl_running_xacts xlrec; XLogRecPtr recptr; + xlrec.dbid = CurrRunningXacts->dbid; xlrec.xcnt = CurrRunningXacts->xcnt; xlrec.subxcnt = CurrRunningXacts->subxcnt; xlrec.subxid_overflow = (CurrRunningXacts->subxid_status != SUBXIDS_IN_ARRAY); diff --git a/src/include/access/genam.h b/src/include/access/genam.h index b69320a7fc8..de55821e414 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -136,6 +136,7 @@ typedef struct IndexOrderByDistance bool isnull; } IndexOrderByDistance; + /* * generalized index_ interface routines (in indexam.c) */ diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 10c18d39ff8..13ae3ad4fbb 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -32,7 +32,7 @@ /* * Each page of XLOG file has a header like this: */ -#define XLOG_PAGE_MAGIC 0xD11E /* can be used as WAL version indicator */ +#define XLOG_PAGE_MAGIC 0xD11F /* can be used as WAL version indicator */ typedef struct XLogPageHeaderData { diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 2e10e3c814d..93b7816c09c 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -310,6 +310,15 @@ extern void PreventCommandIfReadOnly(const char *cmdname); extern void PreventCommandIfParallelMode(const char *cmdname); extern void PreventCommandDuringRecovery(const char *cmdname); +/* in replication/snapbuild.c */ + +/* + * Keep track of whether logical decoding in this backend promised not to + * access shared catalogs, as a safety check. This is checked by genam.c when + * a catalog scan takes place to verify that no shared catalogs are accessed. + */ +extern bool accessSharedCatalogsInDecoding; + /***************************************************************************** * pdir.h -- * * POSTGRES directory path definitions. * diff --git a/src/include/replication/output_plugin.h b/src/include/replication/output_plugin.h index 842fcde67f9..917f3cff232 100644 --- a/src/include/replication/output_plugin.h +++ b/src/include/replication/output_plugin.h @@ -27,6 +27,7 @@ typedef struct OutputPluginOptions { OutputPluginOutputType output_type; bool receive_rewrites; + bool need_shared_catalogs; } OutputPluginOptions; /* diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h index a22a83a2f23..d02530a912a 100644 --- a/src/include/replication/snapbuild.h +++ b/src/include/replication/snapbuild.h @@ -92,7 +92,8 @@ extern void SnapBuildProcessNewCid(SnapBuild *builder, TransactionId xid, XLogRecPtr lsn, xl_heap_new_cid *xlrec); extern void SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, - xl_running_xacts *running); + xl_running_xacts *running, + bool db_specific); extern void SnapBuildSerializationPoint(SnapBuild *builder, XLogRecPtr lsn); extern bool SnapBuildSnapshotExists(XLogRecPtr lsn); diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index d718a5b542f..ec89c448220 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -47,7 +47,7 @@ extern bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid); extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc); -extern RunningTransactions GetRunningTransactionData(void); +extern RunningTransactions GetRunningTransactionData(Oid dbid); extern bool TransactionIdIsInProgress(TransactionId xid); extern TransactionId GetOldestNonRemovableTransactionId(Relation rel); diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index 6a314c693cd..8715c08e94f 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -126,6 +126,7 @@ typedef enum typedef struct RunningTransactionsData { + Oid dbid; /* only track xacts in this database */ int xcnt; /* # of xact ids in xids[] */ int subxcnt; /* # of subxact ids in xids[] */ subxids_array_status subxid_status; @@ -143,7 +144,7 @@ typedef RunningTransactionsData *RunningTransactions; extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid); extern void LogAccessExclusiveLockPrepare(void); -extern XLogRecPtr LogStandbySnapshot(void); +extern XLogRecPtr LogStandbySnapshot(Oid dbid); extern void LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs, bool relcacheInitFileInval); diff --git a/src/include/storage/standbydefs.h b/src/include/storage/standbydefs.h index 231d251fd51..e75b7078766 100644 --- a/src/include/storage/standbydefs.h +++ b/src/include/storage/standbydefs.h @@ -46,6 +46,7 @@ typedef struct xl_standby_locks */ typedef struct xl_running_xacts { + Oid dbid; /* only track xacts in this database */ int xcnt; /* # of xact ids in xids[] */ int subxcnt; /* # of subxact ids in xids[] */ bool subxid_overflow; /* snapshot overflowed, subxids missing */ -- 2.47.3 --qs77q6fpwolne4ds Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="v56-0002-Reserve-replication-slots-specifically-for-REPAC.patch" ^ permalink raw reply [nested|flat] 7+ messages in thread
end of thread, other threads:[~2026-04-06 22:07 UTC | newest] Thread overview: 7+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2017-02-16 06:56 [PATCH 1/2] Allow dropping partitioned table without CASCADE amit <amitlangote09@gmail.com> 2017-02-16 06:56 [PATCH] Allow dropping partitioned table without CASCADE amit <amitlangote09@gmail.com> 2017-02-16 06:56 [PATCH 1/2] Allow dropping partitioned table without CASCADE amit <amitlangote09@gmail.com> 2017-02-16 06:56 [PATCH] Allow dropping partitioned table without CASCADE amit <amitlangote09@gmail.com> 2017-02-16 06:56 [PATCH] Allow dropping partitioned table without CASCADE amit <amitlangote09@gmail.com> 2017-02-16 06:56 [PATCH] Allow dropping partitioned table without CASCADE amit <amitlangote09@gmail.com> 2026-04-06 22:07 [PATCH v56 1/3] Allow logical replication snapshots to be database-specific Álvaro Herrera <alvherre@kurilemu.de>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox