Fix failure to remove dependencies when a partition is detached.

Otherwise, dropping the partitioned table will automatically drop
any previously-detached children, which would be unfortunate.

Ashutosh Bapat and Rahila Syed, reviewed by Amit Langote and by me.

Discussion: http://postgr.es/m/CAFjFpRdOwHuGj45i25iLQ4QituA0uH6RuLX1h5deD4KBZJ25yg@mail.gmail.com
This commit is contained in:
Robert Haas 2017-06-13 11:51:42 -04:00
parent 506b565831
commit ee252f074b
3 changed files with 44 additions and 14 deletions

View File

@ -283,6 +283,14 @@ struct DropRelationCallbackState
#define ATT_COMPOSITE_TYPE 0x0010 #define ATT_COMPOSITE_TYPE 0x0010
#define ATT_FOREIGN_TABLE 0x0020 #define ATT_FOREIGN_TABLE 0x0020
/*
* Partition tables are expected to be dropped when the parent partitioned
* table gets dropped. Hence for partitioning we use AUTO dependency.
* Otherwise, for regular inheritance use NORMAL dependency.
*/
#define child_dependency_type(child_is_partition) \
((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
static void truncate_check_rel(Relation rel); static void truncate_check_rel(Relation rel);
static List *MergeAttributes(List *schema, List *supers, char relpersistence, static List *MergeAttributes(List *schema, List *supers, char relpersistence,
bool is_partition, List **supOids, List **supconstr, bool is_partition, List **supOids, List **supconstr,
@ -439,7 +447,8 @@ static void ATExecEnableDisableRule(Relation rel, char *rulename,
static void ATPrepAddInherit(Relation child_rel); static void ATPrepAddInherit(Relation child_rel);
static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode); static ObjectAddress ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode); static ObjectAddress ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid); static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
DependencyType deptype);
static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode); static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
static void ATExecDropOf(Relation rel, LOCKMODE lockmode); static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode); static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
@ -2367,14 +2376,8 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
childobject.objectId = relationId; childobject.objectId = relationId;
childobject.objectSubId = 0; childobject.objectSubId = 0;
/* recordDependencyOn(&childobject, &parentobject,
* Partition tables are expected to be dropped when the parent partitioned child_dependency_type(child_is_partition));
* table gets dropped.
*/
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 * Post creation hook of this inheritance. Since object_access_hook
@ -11666,7 +11669,8 @@ RemoveInheritance(Relation child_rel, Relation parent_rel)
drop_parent_dependency(RelationGetRelid(child_rel), drop_parent_dependency(RelationGetRelid(child_rel),
RelationRelationId, RelationRelationId,
RelationGetRelid(parent_rel)); RelationGetRelid(parent_rel),
child_dependency_type(child_is_partition));
/* /*
* Post alter hook of this inherits. Since object_access_hook doesn't take * Post alter hook of this inherits. Since object_access_hook doesn't take
@ -11686,7 +11690,8 @@ RemoveInheritance(Relation child_rel, Relation parent_rel)
* through pg_depend. * through pg_depend.
*/ */
static void static void
drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid) drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
DependencyType deptype)
{ {
Relation catalogRelation; Relation catalogRelation;
SysScanDesc scan; SysScanDesc scan;
@ -11718,7 +11723,7 @@ drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid)
if (dep->refclassid == refclassid && if (dep->refclassid == refclassid &&
dep->refobjid == refobjid && dep->refobjid == refobjid &&
dep->refobjsubid == 0 && dep->refobjsubid == 0 &&
dep->deptype == DEPENDENCY_NORMAL) dep->deptype == deptype)
CatalogTupleDelete(catalogRelation, &depTuple->t_self); CatalogTupleDelete(catalogRelation, &depTuple->t_self);
} }
@ -11839,7 +11844,8 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
/* If the table was already typed, drop the existing dependency. */ /* If the table was already typed, drop the existing dependency. */
if (rel->rd_rel->reloftype) if (rel->rd_rel->reloftype)
drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype); drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
DEPENDENCY_NORMAL);
/* Record a dependency on the new type. */ /* Record a dependency on the new type. */
tableobj.classId = RelationRelationId; tableobj.classId = RelationRelationId;
@ -11892,7 +11898,8 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode)
* table is presumed enough rights. No lock required on the type, either. * table is presumed enough rights. No lock required on the type, either.
*/ */
drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype); drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
DEPENDENCY_NORMAL);
/* Clear pg_class.reloftype */ /* Clear pg_class.reloftype */
relationRelation = heap_open(RelationRelationId, RowExclusiveLock); relationRelation = heap_open(RelationRelationId, RowExclusiveLock);

View File

@ -3385,6 +3385,19 @@ SELECT coninhcount, conislocal FROM pg_constraint WHERE conrelid = 'part_3_4'::r
(1 row) (1 row)
DROP TABLE part_3_4; DROP TABLE part_3_4;
-- check that a detached partition is not dropped on dropping a partitioned table
CREATE TABLE range_parted2 (
a int
) PARTITION BY RANGE(a);
CREATE TABLE part_rp PARTITION OF range_parted2 FOR VALUES FROM (0) to (100);
ALTER TABLE range_parted2 DETACH PARTITION part_rp;
DROP TABLE range_parted2;
SELECT * from part_rp;
a
---
(0 rows)
DROP TABLE part_rp;
-- Check ALTER TABLE commands for partitioned tables and partitions -- Check ALTER TABLE commands for partitioned tables and partitions
-- cannot add/drop column to/from *only* the parent -- cannot add/drop column to/from *only* the parent
ALTER TABLE ONLY list_parted2 ADD COLUMN c int; ALTER TABLE ONLY list_parted2 ADD COLUMN c int;

View File

@ -2204,6 +2204,16 @@ SELECT attinhcount, attislocal FROM pg_attribute WHERE attrelid = 'part_3_4'::re
SELECT coninhcount, conislocal FROM pg_constraint WHERE conrelid = 'part_3_4'::regclass AND conname = 'check_a'; SELECT coninhcount, conislocal FROM pg_constraint WHERE conrelid = 'part_3_4'::regclass AND conname = 'check_a';
DROP TABLE part_3_4; DROP TABLE part_3_4;
-- check that a detached partition is not dropped on dropping a partitioned table
CREATE TABLE range_parted2 (
a int
) PARTITION BY RANGE(a);
CREATE TABLE part_rp PARTITION OF range_parted2 FOR VALUES FROM (0) to (100);
ALTER TABLE range_parted2 DETACH PARTITION part_rp;
DROP TABLE range_parted2;
SELECT * from part_rp;
DROP TABLE part_rp;
-- Check ALTER TABLE commands for partitioned tables and partitions -- Check ALTER TABLE commands for partitioned tables and partitions
-- cannot add/drop column to/from *only* the parent -- cannot add/drop column to/from *only* the parent