From 6bfcd9ae32b067f7cee38799bf34d64f7ca44c73 Mon Sep 17 00:00:00 2001 From: Sami Imseih Date: Thu, 3 Sep 2026 18:50:49 +0000 Subject: [PATCH v18 1/3] Preserve index DEPENDS ON EXTENSION links across ALTER COLUMN TYPE A DEPENDS ON EXTENSION link on an index was silently lost when ALTER TABLE ... ALTER COLUMN TYPE rebuilt the index. An auto-extension dependency is not expressible as a CREATE INDEX clause, so it is not reproduced by the pg_get_indexdef_string() that recreates the index. Capture any auto-extension dependencies before dropping the index and then recreate them after creating the new index. --- src/backend/commands/indexcmds.c | 17 +++++++++++++++++ src/backend/commands/tablecmds.c | 7 +++++++ src/include/nodes/parsenodes.h | 1 + src/test/regress/expected/alter_table.out | 21 +++++++++++++++++++++ src/test/regress/sql/alter_table.sql | 16 ++++++++++++++++ 5 files changed, 62 insertions(+) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 5a0312fe772..620359a7a32 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -25,6 +25,7 @@ #include "access/tableam.h" #include "access/xact.h" #include "catalog/catalog.h" +#include "catalog/dependency.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/namespace.h" @@ -33,6 +34,7 @@ #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" #include "catalog/pg_database.h" +#include "catalog/pg_extension.h" #include "catalog/pg_inherits.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" @@ -1324,6 +1326,21 @@ DefineIndex(ParseState *pstate, CreateComments(indexRelationId, RelationRelationId, 0, stmt->idxcomment); + /* Recreate any DEPENDS ON EXTENSION links from the old index. */ + if (stmt->idxextensionOids != NIL) + { + ObjectAddress indexAddress, + extensionAddress; + + ObjectAddressSet(indexAddress, RelationRelationId, indexRelationId); + foreach_oid(extensionOid, stmt->idxextensionOids) + { + ObjectAddressSet(extensionAddress, ExtensionRelationId, extensionOid); + recordDependencyOn(&indexAddress, &extensionAddress, + DEPENDENCY_AUTO_EXTENSION); + } + } + if (partitioned) { PartitionDesc partdesc; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index fd144d783d9..d25a7cc16ce 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -30,6 +30,7 @@ #include "access/xlog.h" #include "access/xloginsert.h" #include "catalog/catalog.h" +#include "catalog/dependency.h" #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/namespace.h" @@ -16377,6 +16378,9 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, Oid ownerId, stmt->reset_default_tblspc = true; /* keep the index's comment */ stmt->idxcomment = GetComment(oldId, RelationRelationId, 0); + /* keep any DEPENDS ON EXTENSION links */ + stmt->idxextensionOids = + getAutoExtensionsOfObject(RelationRelationId, oldId); newcmd = makeNode(AlterTableCmd); newcmd->subtype = AT_ReAddIndex; @@ -16406,6 +16410,9 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, Oid ownerId, /* keep any comment on the index */ indstmt->idxcomment = GetComment(indoid, RelationRelationId, 0); + /* keep any DEPENDS ON EXTENSION links */ + indstmt->idxextensionOids = + getAutoExtensionsOfObject(RelationRelationId, indoid); indstmt->reset_default_tblspc = true; cmd->subtype = AT_ReAddIndex; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index a0ab2b885e8..78a393b79fb 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3613,6 +3613,7 @@ typedef struct IndexStmt Node *whereClause; /* qualification (partial-index predicate) */ List *excludeOpNames; /* exclusion operator names, or NIL if none */ char *idxcomment; /* comment to apply to index, or NULL */ + List *idxextensionOids; /* extensions to depend on after a rebuild */ Oid indexOid; /* OID of an existing index, if any */ RelFileNumber oldNumber; /* relfilenumber of existing storage, if any */ SubTransactionId oldCreateSubid; /* rd_createSubid of oldNumber */ diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index e167a41ce79..62bdf95860f 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2326,6 +2326,27 @@ select conname, obj_description(oid, 'pg_constraint') as desc -- Don't remove this DROP, it exposes bug #15672 drop table at_partitioned; +-- Auto-extension dependencies should still exist after an ALTER COLUMN TYPE +create table at_reb_extdep (id int not null, val int not null); +create index at_reb_extdep_expr on at_reb_extdep ((val + 1)); +alter table at_reb_extdep add constraint at_reb_extdep_c unique (id, val); +alter index at_reb_extdep_expr depends on extension plpgsql; +alter index at_reb_extdep_c depends on extension plpgsql; +alter table at_reb_extdep alter column val type bigint; +select c.relname, d.deptype, e.extname + from pg_depend d join pg_class c on c.oid = d.objid + join pg_extension e on e.oid = d.refobjid + where d.classid = 'pg_class'::regclass + and c.relname in ('at_reb_extdep_expr', 'at_reb_extdep_c') + and d.refclassid = 'pg_extension'::regclass + order by c.relname; + relname | deptype | extname +--------------------+---------+--------- + at_reb_extdep_c | x | plpgsql + at_reb_extdep_expr | x | plpgsql +(2 rows) + +drop table at_reb_extdep; -- disallow recursive containment of row types create temp table recur1 (f1 int); alter table recur1 add column f2 recur1; -- fails diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 9f6c2a4bb08..4cdf476395d 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1531,6 +1531,22 @@ select conname, obj_description(oid, 'pg_constraint') as desc -- Don't remove this DROP, it exposes bug #15672 drop table at_partitioned; +-- Auto-extension dependencies should still exist after an ALTER COLUMN TYPE +create table at_reb_extdep (id int not null, val int not null); +create index at_reb_extdep_expr on at_reb_extdep ((val + 1)); +alter table at_reb_extdep add constraint at_reb_extdep_c unique (id, val); +alter index at_reb_extdep_expr depends on extension plpgsql; +alter index at_reb_extdep_c depends on extension plpgsql; +alter table at_reb_extdep alter column val type bigint; +select c.relname, d.deptype, e.extname + from pg_depend d join pg_class c on c.oid = d.objid + join pg_extension e on e.oid = d.refobjid + where d.classid = 'pg_class'::regclass + and c.relname in ('at_reb_extdep_expr', 'at_reb_extdep_c') + and d.refclassid = 'pg_extension'::regclass + order by c.relname; +drop table at_reb_extdep; + -- disallow recursive containment of row types create temp table recur1 (f1 int); alter table recur1 add column f2 recur1; -- fails -- 2.50.1