diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index 54688094f58..d7fb1ef359c 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -175,6 +175,13 @@ recordMultipleDependencies(const ObjectAddress *depender, * existed), so we must check for a pre-existing extension membership entry. * Passing false is a guarantee that the object is newly created, and so * could not already be a member of any extension. + * + * Note: isReplace = true is typically used when updating a object in + * CREATE OR REPLACE and similar commands. The net effect is that if an + * extension script uses such a command on a pre-existing free-standing + * object, the object will be absorbed into the extension. If the object + * is already a member of some other extension, the command will fail. + * This behavior is desirable for cases such as replacing a shell type. */ void recordDependencyOnCurrentExtension(const ObjectAddress *object, diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 6c270f93389..4c5a56cb094 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -268,7 +268,7 @@ OperatorShellMake(const char *operatorName, CatalogTupleInsert(pg_operator_desc, tup); /* Add dependencies for the entry */ - makeOperatorDependencies(tup, false); + makeOperatorDependencies(tup, true, false); heap_freetuple(tup); @@ -546,7 +546,7 @@ OperatorCreate(const char *operatorName, } /* Add dependencies for the entry */ - address = makeOperatorDependencies(tup, isUpdate); + address = makeOperatorDependencies(tup, true, isUpdate); /* Post creation hook for new operator */ InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0); @@ -766,11 +766,17 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete) * complete operator, a new shell operator, a just-updated shell, * or an operator that's being modified by ALTER OPERATOR). * + * makeExtensionDep should be true when making a new operator or + * replacing a shell, false for ALTER OPERATOR. Passing false + * will prevent any change in the operator's extension membership. + * * NB: the OidIsValid tests in this routine are necessary, in case * the given operator is a shell. */ ObjectAddress -makeOperatorDependencies(HeapTuple tuple, bool isUpdate) +makeOperatorDependencies(HeapTuple tuple, + bool makeExtensionDep, + bool isUpdate) { Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple); ObjectAddress myself, @@ -857,7 +863,8 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate) oper->oprowner); /* Dependency on extension */ - recordDependencyOnCurrentExtension(&myself, true); + if (makeExtensionDep) + recordDependencyOnCurrentExtension(&myself, true); return myself; } diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 6f9b5471daf..cdce22f394f 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -167,6 +167,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) 0, false, false, + true, /* make extension dependency */ false); /* Post creation hook for new shell type */ @@ -504,6 +505,7 @@ TypeCreate(Oid newTypeOid, relationKind, isImplicitArray, isDependentType, + true, /* make extension dependency */ rebuildDeps); /* Post creation hook for new type */ @@ -537,13 +539,17 @@ TypeCreate(Oid newTypeOid, * isDependentType is true if this is an implicit array or relation rowtype; * that means it doesn't need its own dependencies on owner etc. * - * If rebuild is true, we remove existing dependencies and rebuild them - * from scratch. This is needed for ALTER TYPE, and also when replacing - * a shell type. We don't remove an existing extension dependency, though. - * (That means an extension can't absorb a shell type created in another - * extension, nor ALTER a type created by another extension. Also, if it - * replaces a free-standing shell type or ALTERs a free-standing type, - * that type will become a member of the extension.) + * We make an extension-membership dependency if we're in an extension + * script and makeExtensionDep is true (and isDependentType isn't true). + * makeExtensionDep should be true when creating a new type or replacing a + * shell type, but not for ALTER TYPE on an existing type. Passing false + * causes the type's extension membership to be left alone. + * + * rebuild should be true if this is a pre-existing type. We will remove + * existing dependencies and rebuild them from scratch. This is needed for + * ALTER TYPE, and also when replacing a shell type. We don't remove any + * existing extension dependency, though (hence, if makeExtensionDep is also + * true and the type belongs to some other extension, an error will occur). */ void GenerateTypeDependencies(HeapTuple typeTuple, @@ -553,6 +559,7 @@ GenerateTypeDependencies(HeapTuple typeTuple, char relationKind, /* only for relation rowtypes */ bool isImplicitArray, bool isDependentType, + bool makeExtensionDep, bool rebuild) { Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple); @@ -611,7 +618,8 @@ GenerateTypeDependencies(HeapTuple typeTuple, recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0, typeForm->typowner, typacl); - recordDependencyOnCurrentExtension(&myself, rebuild); + if (makeExtensionDep) + recordDependencyOnCurrentExtension(&myself, rebuild); } /* Normal dependencies on the I/O and support functions */ diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index fbd7d8d062f..eb50f60ed13 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -542,7 +542,7 @@ AlterOperator(AlterOperatorStmt *stmt) CatalogTupleUpdate(catalog, &tup->t_self, tup); - address = makeOperatorDependencies(tup, true); + address = makeOperatorDependencies(tup, false, true); InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0); diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 58ec65c6afc..106d9703ac0 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -2690,6 +2690,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) 0, /* relation kind is n/a */ false, /* a domain isn't an implicit array */ false, /* nor is it any kind of dependent type */ + false, /* don't touch extension membership */ true); /* We do need to rebuild dependencies */ InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0); @@ -4430,6 +4431,7 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, 0, /* we rejected composite types above */ isImplicitArray, /* it might be an array */ isImplicitArray, /* dependent iff it's array */ + false, /* don't touch extension membership */ true); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index d32fcdc64e6..a40e38a5d87 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -100,7 +100,9 @@ extern ObjectAddress OperatorCreate(const char *operatorName, bool canMerge, bool canHash); -extern ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate); +extern ObjectAddress makeOperatorDependencies(HeapTuple tuple, + bool makeExtensionDep, + bool isUpdate); extern void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 33557760e19..0ece1e03d74 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -388,6 +388,7 @@ extern void GenerateTypeDependencies(HeapTuple typeTuple, * rowtypes */ bool isImplicitArray, bool isDependentType, + bool makeExtensionDep, bool rebuild); extern void RenameTypeInternal(Oid typeOid, const char *newTypeName,