@@ -3492,7 +3492,7 @@ renameatt_internal(Oid myrelid,
3492
3492
* expected_parents will only be 0 if we are not already recursing.
3493
3493
*/
3494
3494
if (expected_parents == 0 &&
3495
- find_inheritance_children(myrelid, true, NoLock, NULL ) != NIL)
3495
+ find_inheritance_children(myrelid, NoLock) != NIL)
3496
3496
ereport(ERROR,
3497
3497
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3498
3498
errmsg("inherited column \"%s\" must be renamed in child tables too",
@@ -3691,7 +3691,7 @@ rename_constraint_internal(Oid myrelid,
3691
3691
else
3692
3692
{
3693
3693
if (expected_parents == 0 &&
3694
- find_inheritance_children(myrelid, true, NoLock, NULL ) != NIL)
3694
+ find_inheritance_children(myrelid, NoLock) != NIL)
3695
3695
ereport(ERROR,
3696
3696
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3697
3697
errmsg("inherited constraint \"%s\" must be renamed in child tables too",
@@ -6565,7 +6565,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
6565
6565
*/
6566
6566
if (colDef->identity &&
6567
6567
recurse &&
6568
- find_inheritance_children(myrelid, true, NoLock, NULL ) != NIL)
6568
+ find_inheritance_children(myrelid, NoLock) != NIL)
6569
6569
ereport(ERROR,
6570
6570
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6571
6571
errmsg("cannot recursively add identity column to table that has child tables")));
@@ -6811,7 +6811,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
6811
6811
* use find_all_inheritors to do it in one pass.
6812
6812
*/
6813
6813
children =
6814
- find_inheritance_children(RelationGetRelid(rel), true, lockmode, NULL );
6814
+ find_inheritance_children(RelationGetRelid(rel), lockmode);
6815
6815
6816
6816
/*
6817
6817
* If we are told not to recurse, there had better not be any child
@@ -7674,7 +7674,7 @@ ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recurs
7674
7674
* resulting state can be properly dumped and restored.
7675
7675
*/
7676
7676
if (!recurse &&
7677
- find_inheritance_children(RelationGetRelid(rel), true, lockmode, NULL ))
7677
+ find_inheritance_children(RelationGetRelid(rel), lockmode))
7678
7678
ereport(ERROR,
7679
7679
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7680
7680
errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
@@ -8282,7 +8282,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
8282
8282
* use find_all_inheritors to do it in one pass.
8283
8283
*/
8284
8284
children =
8285
- find_inheritance_children(RelationGetRelid(rel), true, lockmode, NULL );
8285
+ find_inheritance_children(RelationGetRelid(rel), lockmode);
8286
8286
8287
8287
if (children)
8288
8288
{
@@ -8770,7 +8770,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
8770
8770
* use find_all_inheritors to do it in one pass.
8771
8771
*/
8772
8772
children =
8773
- find_inheritance_children(RelationGetRelid(rel), true, lockmode, NULL );
8773
+ find_inheritance_children(RelationGetRelid(rel), lockmode);
8774
8774
8775
8775
/*
8776
8776
* Check if ONLY was specified with ALTER TABLE. If so, allow the
@@ -11303,8 +11303,7 @@ ATExecDropConstraint(Relation rel, const char *constrName,
11303
11303
* use find_all_inheritors to do it in one pass.
11304
11304
*/
11305
11305
if (!is_no_inherit_constraint)
11306
- children = find_inheritance_children(RelationGetRelid(rel), true,
11307
- lockmode, NULL);
11306
+ children = find_inheritance_children(RelationGetRelid(rel), lockmode);
11308
11307
else
11309
11308
children = NIL;
11310
11309
@@ -11688,8 +11687,7 @@ ATPrepAlterColumnType(List **wqueue,
11688
11687
}
11689
11688
}
11690
11689
else if (!recursing &&
11691
- find_inheritance_children(RelationGetRelid(rel), true,
11692
- NoLock, NULL) != NIL)
11690
+ find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
11693
11691
ereport(ERROR,
11694
11692
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
11695
11693
errmsg("type of inherited column \"%s\" must be changed in child tables too",
@@ -14601,7 +14599,8 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
14601
14599
* MarkInheritDetached
14602
14600
*
14603
14601
* Set inhdetachpending for a partition, for ATExecDetachPartition
14604
- * in concurrent mode.
14602
+ * in concurrent mode. While at it, verify that no other partition is
14603
+ * already pending detach.
14605
14604
*/
14606
14605
static void
14607
14606
MarkInheritDetached(Relation child_rel, Relation parent_rel)
@@ -14617,32 +14616,45 @@ MarkInheritDetached(Relation child_rel, Relation parent_rel)
14617
14616
Assert(parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
14618
14617
14619
14618
/*
14620
- * Find pg_inherits entries by inhrelid.
14619
+ * Find pg_inherits entries by inhparent. (We need to scan them all in
14620
+ * order to verify that no other partition is pending detach.)
14621
14621
*/
14622
14622
catalogRelation = table_open(InheritsRelationId, RowExclusiveLock);
14623
14623
ScanKeyInit(&key,
14624
- Anum_pg_inherits_inhrelid ,
14624
+ Anum_pg_inherits_inhparent ,
14625
14625
BTEqualStrategyNumber, F_OIDEQ,
14626
- ObjectIdGetDatum(RelationGetRelid(child_rel )));
14627
- scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId ,
14626
+ ObjectIdGetDatum(RelationGetRelid(parent_rel )));
14627
+ scan = systable_beginscan(catalogRelation, InheritsParentIndexId ,
14628
14628
true, NULL, 1, &key);
14629
14629
14630
14630
while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
14631
14631
{
14632
- HeapTuple newtup ;
14632
+ Form_pg_inherits inhForm ;
14633
14633
14634
- if (((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent !=
14635
- RelationGetRelid(parent_rel))
14636
- elog(ERROR, "bad parent tuple found for partition %u",
14637
- RelationGetRelid(child_rel));
14634
+ inhForm = (Form_pg_inherits) GETSTRUCT(inheritsTuple);
14635
+ if (inhForm->inhdetachpending)
14636
+ ereport(ERROR,
14637
+ errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
14638
+ errmsg("partition \"%s\" already pending detach in partitioned table \"%s.%s\"",
14639
+ get_rel_name(inhForm->inhrelid),
14640
+ get_namespace_name(parent_rel->rd_rel->relnamespace),
14641
+ RelationGetRelationName(parent_rel)),
14642
+ errhint("Use ALTER TABLE ... DETACH PARTITION ... FINALIZE to complete the detach operation."));
14643
+
14644
+ if (inhForm->inhrelid == RelationGetRelid(child_rel))
14645
+ {
14646
+ HeapTuple newtup;
14638
14647
14639
- newtup = heap_copytuple(inheritsTuple);
14640
- ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
14648
+ newtup = heap_copytuple(inheritsTuple);
14649
+ ((Form_pg_inherits) GETSTRUCT(newtup))->inhdetachpending = true;
14641
14650
14642
- CatalogTupleUpdate(catalogRelation,
14643
- &inheritsTuple->t_self,
14644
- newtup);
14645
- found = true;
14651
+ CatalogTupleUpdate(catalogRelation,
14652
+ &inheritsTuple->t_self,
14653
+ newtup);
14654
+ found = true;
14655
+ heap_freetuple(newtup);
14656
+ /* keep looking, to ensure we catch others pending detach */
14657
+ }
14646
14658
}
14647
14659
14648
14660
/* Done */
0 commit comments