diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f798794556..ced4f9a658 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -643,7 +643,7 @@ static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel, List *partConstraint, bool validate_default); static void CloneRowTriggersToPartition(Relation parent, Relation partition); -static void DetachAddConstraintIfNeeded(List **wqueue, Relation partRel); +static ObjectAddress DetachAddConstraintIfNeeded(List **wqueue, Relation partRel); static void DropClonedTriggersFromPartition(Oid partitionId); static ObjectAddress ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, RangeVar *name, @@ -19579,12 +19579,14 @@ ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, LOCKTAG tag; char *parentrelname; char *partrelname; + ObjectAddress consAddress = InvalidObjectAddress; + PartitionDesc desc; /* * Add a new constraint to the partition being detached, which * supplants the partition constraint (unless there is one already). */ - DetachAddConstraintIfNeeded(wqueue, partRel); + consAddress = DetachAddConstraintIfNeeded(wqueue, partRel); /* * We're almost done now; the only traces that remain are the @@ -19653,6 +19655,32 @@ ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, errmsg("partition \"%s\" was removed concurrently", partrelname))); tab->rel = rel; + + /* + * The hash partition's relpartbounds contains the oid of the parent + * partition. If the parent partition is gone, a error is thrown when + * checking constraints. + */ + desc = RelationGetPartitionDesc(rel, true); + if (desc && desc->boundinfo->strategy == PARTITION_STRATEGY_HASH && + OidIsValid(consAddress.objectId)) + { + Relation constraintRelation; + HeapTuple constraintTuple; + Form_pg_constraint con; + + constraintRelation = table_open(ConstraintRelationId, RowExclusiveLock); + constraintTuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(consAddress.objectId)); + if (!HeapTupleIsValid(constraintTuple)) + elog(ERROR, "cache lookup failed for constraint %u", consAddress.objectId); + con = (Form_pg_constraint) GETSTRUCT(constraintTuple); + + ATExecDropConstraint(partRel, con->conname.data, DROP_CASCADE, true, + true, ShareUpdateExclusiveLock); + + heap_freetuple(constraintTuple); + table_close(constraintRelation, RowExclusiveLock); + } } /* Do the final part of detaching */ @@ -19946,10 +19974,11 @@ ATExecDetachPartitionFinalize(Relation rel, RangeVar *name) * a dupe if an constraint already exists which implies the needed * constraint. */ -static void +static ObjectAddress DetachAddConstraintIfNeeded(List **wqueue, Relation partRel) { List *constraintExpr; + ObjectAddress address = InvalidObjectAddress; constraintExpr = RelationGetPartitionQual(partRel); constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr); @@ -19976,9 +20005,12 @@ DetachAddConstraintIfNeeded(List **wqueue, Relation partRel) n->initially_valid = true; n->skip_validation = true; /* It's a re-add, since it nominally already exists */ - ATAddCheckNNConstraint(wqueue, tab, partRel, n, - true, false, true, ShareUpdateExclusiveLock); + address = ATAddCheckNNConstraint(wqueue, tab, partRel, n, + true, false, true, + ShareUpdateExclusiveLock); } + + return address; } /* diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 7666c76238..af0d3c06a6 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -4359,6 +4359,23 @@ Check constraints: "part_rp100_a_check" CHECK (a >= 123 AND a < 133 AND a IS NOT NULL) DROP TABLE range_parted2; +CREATE TABLE hash_parted2 ( + a int, + b int +) PARTITION BY HASH (a part_test_int4_ops); +CREATE TABLE hpart2_1 PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 4, REMAINDER 0); +ALTER TABLE hash_parted2 DETACH PARTITION hpart2_1 CONCURRENTLY; +DROP TABLE hash_parted2; +-- constraint should not be created +\d hpart2_1 + Table "public.hpart2_1" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + a | integer | | | + b | integer | | | + +INSERT INTO hpart2_1 SELECT 1; +DROP TABLE hpart2_1; -- Check ALTER TABLE commands for partitioned tables and partitions -- cannot add/drop column to/from *only* the parent ALTER TABLE ONLY list_parted2 ADD COLUMN c int; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 9df5a63bdf..55f2635ab9 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2786,6 +2786,18 @@ ALTER TABLE range_parted2 DETACH PARTITION part_rp100 CONCURRENTLY; \d part_rp100 DROP TABLE range_parted2; +CREATE TABLE hash_parted2 ( + a int, + b int +) PARTITION BY HASH (a part_test_int4_ops); +CREATE TABLE hpart2_1 PARTITION OF hash_parted2 FOR VALUES WITH (MODULUS 4, REMAINDER 0); +ALTER TABLE hash_parted2 DETACH PARTITION hpart2_1 CONCURRENTLY; +DROP TABLE hash_parted2; +-- constraint should not be created +\d hpart2_1 +INSERT INTO hpart2_1 SELECT 1; +DROP TABLE hpart2_1; + -- Check ALTER TABLE commands for partitioned tables and partitions -- cannot add/drop column to/from *only* the parent