From 4631ce7d3fb0d14710e85c79c88223116701c843 Mon Sep 17 00:00:00 2001 From: Dilip Kumar Date: Thu, 29 Oct 2026 12:15:53 +0000 Subject: [PATCH v1] Fix ALTER COLUMN TYPE on INCLUDE column of index used by a foreign key ALTER COLUMN TYPE collects the indexes and constraints that depend directly on the altered column, drops them in ATPostAlterTypeCleanup() using DROP_RESTRICT, and recreates them afterwards. A foreign key constraint depends both on its referenced columns and on the unique index supporting them, so altering a key column of that index rebuilds the foreign key along with the index. However, a foreign key does not depend on the INCLUDE columns of its supporting index. Altering such a column therefore queued the index for rebuilding, but not the foreign key, and the drop failed: To fix, whenever an index is remembered for rebuilding, either directly or as the index of a constraint being rebuilt, also remember any foreign key constraints that depend on it. They are then dropped and re-added together with the index, the same way as when a key column is altered. --- src/backend/commands/tablecmds.c | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 93ad49e59fd..e07daff73fe 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -667,6 +667,7 @@ static void RememberAllDependentForRebuilding(AlteredTableInfo *tab, AlterTableT static void RememberWholeRowDependentForRebuilding(AlteredTableInfo *tab, AlterTableType subtype, Relation rel); static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab); static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab); +static void RememberFKsOnIndexForRebuilding(Oid indoid, AlteredTableInfo *tab); static void RememberStatisticsForRebuilding(Oid stxoid, AlteredTableInfo *tab); static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode); @@ -16002,6 +16003,7 @@ RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab) { RememberReplicaIdentityForRebuilding(indoid, tab); RememberClusterOnForRebuilding(indoid, tab); + RememberFKsOnIndexForRebuilding(indoid, tab); } } } @@ -16053,10 +16055,58 @@ RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab) */ RememberReplicaIdentityForRebuilding(indoid, tab); RememberClusterOnForRebuilding(indoid, tab); + RememberFKsOnIndexForRebuilding(indoid, tab); } } } +/* + * Subroutine for ATExecAlterColumnType: remember any foreign key constraints + * that depend on the given index, which we are about to rebuild. + * + * A foreign key constraint has a dependency on the unique index supporting + * its referenced columns. Usually such a constraint gets remembered anyway, + * because it also depends on the referenced columns themselves. But if the + * column being altered is only an INCLUDE column of that index, the foreign + * key does not depend on it, and dropping the index in + * ATPostAlterTypeCleanup() would fail. So we must rebuild the foreign key + * along with the index. + */ +static void +RememberFKsOnIndexForRebuilding(Oid indoid, AlteredTableInfo *tab) +{ + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple depTup; + + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(indoid)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, 2, key); + + while (HeapTupleIsValid(depTup = systable_getnext(scan))) + { + Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(depTup); + + if (foundDep->classid == ConstraintRelationId && + get_constraint_type(foundDep->objid) == CONSTRAINT_FOREIGN) + RememberConstraintForRebuilding(foundDep->objid, tab); + } + + systable_endscan(scan); + table_close(depRel, AccessShareLock); +} + /* * Subroutine for ATExecAlterColumnType: remember that a statistics object * needs to be rebuilt (which we might already know). -- 2.56.0.385.gac671c819a-goog