Commit 988cccc6 authored by Tom Lane's avatar Tom Lane

Rethink behavior of CREATE OR REPLACE during CREATE EXTENSION.

The original implementation simply did nothing when replacing an existing
object during CREATE EXTENSION.  The folly of this was exposed by a report
from Marc Munro: if the existing object belongs to another extension, we
are left in an inconsistent state.  We should insist that the object does
not belong to another extension, and then add it to the current extension
if not already a member.
parent 6f1be5a6
...@@ -1256,7 +1256,7 @@ heap_create_with_catalog(const char *relname, ...@@ -1256,7 +1256,7 @@ heap_create_with_catalog(const char *relname,
recordDependencyOnOwner(RelationRelationId, relid, ownerid); recordDependencyOnOwner(RelationRelationId, relid, ownerid);
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
if (reloftypeid) if (reloftypeid)
{ {
......
...@@ -132,7 +132,7 @@ CollationCreate(const char *collname, Oid collnamespace, ...@@ -132,7 +132,7 @@ CollationCreate(const char *collname, Oid collnamespace,
collowner); collowner);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new collation */ /* Post creation hook for new collation */
InvokeObjectAccessHook(OAT_POST_CREATE, InvokeObjectAccessHook(OAT_POST_CREATE,
......
...@@ -133,7 +133,7 @@ ConversionCreate(const char *conname, Oid connamespace, ...@@ -133,7 +133,7 @@ ConversionCreate(const char *conname, Oid connamespace,
conowner); conowner);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new conversion */ /* Post creation hook for new conversion */
InvokeObjectAccessHook(OAT_POST_CREATE, InvokeObjectAccessHook(OAT_POST_CREATE,
......
...@@ -130,14 +130,44 @@ recordMultipleDependencies(const ObjectAddress *depender, ...@@ -130,14 +130,44 @@ recordMultipleDependencies(const ObjectAddress *depender,
* *
* This must be called during creation of any user-definable object type * This must be called during creation of any user-definable object type
* that could be a member of an extension. * that could be a member of an extension.
*
* If isReplace is true, the object already existed (or might have already
* 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.
*/ */
void void
recordDependencyOnCurrentExtension(const ObjectAddress *object) recordDependencyOnCurrentExtension(const ObjectAddress *object,
bool isReplace)
{ {
/* Only whole objects can be extension members */
Assert(object->objectSubId == 0);
if (creating_extension) if (creating_extension)
{ {
ObjectAddress extension; ObjectAddress extension;
/* Only need to check for existing membership if isReplace */
if (isReplace)
{
Oid oldext;
oldext = getExtensionOfObject(object->classId, object->objectId);
if (OidIsValid(oldext))
{
/* If already a member of this extension, nothing to do */
if (oldext == CurrentExtensionObject)
return;
/* Already a member of some other extension, so reject */
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of extension \"%s\"",
getObjectDescription(object),
get_extension_name(oldext))));
}
}
/* OK, record it as a member of CurrentExtensionObject */
extension.classId = ExtensionRelationId; extension.classId = ExtensionRelationId;
extension.objectId = CurrentExtensionObject; extension.objectId = CurrentExtensionObject;
extension.objectSubId = 0; extension.objectSubId = 0;
......
...@@ -83,7 +83,7 @@ NamespaceCreate(const char *nspName, Oid ownerId) ...@@ -83,7 +83,7 @@ NamespaceCreate(const char *nspName, Oid ownerId)
recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId); recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new schema */ /* Post creation hook for new schema */
InvokeObjectAccessHook(OAT_POST_CREATE, NamespaceRelationId, nspoid, 0); InvokeObjectAccessHook(OAT_POST_CREATE, NamespaceRelationId, nspoid, 0);
......
...@@ -855,5 +855,5 @@ makeOperatorDependencies(HeapTuple tuple) ...@@ -855,5 +855,5 @@ makeOperatorDependencies(HeapTuple tuple)
oper->oprowner); oper->oprowner);
/* Dependency on extension */ /* Dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, true);
} }
...@@ -564,8 +564,7 @@ ProcedureCreate(const char *procedureName, ...@@ -564,8 +564,7 @@ ProcedureCreate(const char *procedureName,
* Create dependencies for the new function. If we are updating an * Create dependencies for the new function. If we are updating an
* existing function, first delete any existing pg_depend entries. * existing function, first delete any existing pg_depend entries.
* (However, since we are not changing ownership or permissions, the * (However, since we are not changing ownership or permissions, the
* shared dependencies do *not* need to change, and we leave them alone. * shared dependencies do *not* need to change, and we leave them alone.)
* We also don't change any pre-existing extension-membership dependency.)
*/ */
if (is_update) if (is_update)
deleteDependencyRecordsFor(ProcedureRelationId, retval, true); deleteDependencyRecordsFor(ProcedureRelationId, retval, true);
...@@ -619,8 +618,7 @@ ProcedureCreate(const char *procedureName, ...@@ -619,8 +618,7 @@ ProcedureCreate(const char *procedureName,
} }
/* dependency on extension */ /* dependency on extension */
if (!is_update) recordDependencyOnCurrentExtension(&myself, is_update);
recordDependencyOnCurrentExtension(&myself);
heap_freetuple(tup); heap_freetuple(tup);
......
...@@ -480,7 +480,7 @@ TypeCreate(Oid newTypeOid, ...@@ -480,7 +480,7 @@ TypeCreate(Oid newTypeOid,
* *
* If rebuild is true, we remove existing dependencies and rebuild them * If rebuild is true, we remove existing dependencies and rebuild them
* from scratch. This is needed for ALTER TYPE, and also when replacing * from scratch. This is needed for ALTER TYPE, and also when replacing
* a shell type. We don't remove/rebuild extension dependencies, though. * a shell type.
*/ */
void void
GenerateTypeDependencies(Oid typeNamespace, GenerateTypeDependencies(Oid typeNamespace,
...@@ -521,7 +521,7 @@ GenerateTypeDependencies(Oid typeNamespace, ...@@ -521,7 +521,7 @@ GenerateTypeDependencies(Oid typeNamespace,
* For a relation rowtype (that's not a composite type), we should skip * For a relation rowtype (that's not a composite type), we should skip
* these because we'll depend on them indirectly through the pg_class * these because we'll depend on them indirectly through the pg_class
* entry. Likewise, skip for implicit arrays since we'll depend on them * entry. Likewise, skip for implicit arrays since we'll depend on them
* through the element type. The same goes for extension membership. * through the element type.
*/ */
if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) && if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
!isImplicitArray) !isImplicitArray)
...@@ -532,12 +532,11 @@ GenerateTypeDependencies(Oid typeNamespace, ...@@ -532,12 +532,11 @@ GenerateTypeDependencies(Oid typeNamespace,
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
recordDependencyOnOwner(TypeRelationId, typeObjectId, owner); recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
/* dependency on extension */
if (!rebuild)
recordDependencyOnCurrentExtension(&myself);
} }
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, rebuild);
/* Normal dependencies on the I/O functions */ /* Normal dependencies on the I/O functions */
if (OidIsValid(inputProcedure)) if (OidIsValid(inputProcedure))
{ {
......
...@@ -515,7 +515,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) ...@@ -515,7 +515,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId); recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new foreign data wrapper */ /* Post creation hook for new foreign data wrapper */
InvokeObjectAccessHook(OAT_POST_CREATE, InvokeObjectAccessHook(OAT_POST_CREATE,
...@@ -857,7 +857,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt) ...@@ -857,7 +857,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId); recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new foreign server */ /* Post creation hook for new foreign server */
InvokeObjectAccessHook(OAT_POST_CREATE, ForeignServerRelationId, srvId, 0); InvokeObjectAccessHook(OAT_POST_CREATE, ForeignServerRelationId, srvId, 0);
...@@ -1137,7 +1137,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt) ...@@ -1137,7 +1137,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
} }
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new user mapping */ /* Post creation hook for new user mapping */
InvokeObjectAccessHook(OAT_POST_CREATE, UserMappingRelationId, umId, 0); InvokeObjectAccessHook(OAT_POST_CREATE, UserMappingRelationId, umId, 0);
......
...@@ -1489,6 +1489,7 @@ CreateCast(CreateCastStmt *stmt) ...@@ -1489,6 +1489,7 @@ CreateCast(CreateCastStmt *stmt)
char sourcetyptype; char sourcetyptype;
char targettyptype; char targettyptype;
Oid funcid; Oid funcid;
Oid castid;
int nargs; int nargs;
char castcontext; char castcontext;
char castmethod; char castmethod;
...@@ -1734,13 +1735,13 @@ CreateCast(CreateCastStmt *stmt) ...@@ -1734,13 +1735,13 @@ CreateCast(CreateCastStmt *stmt)
tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
simple_heap_insert(relation, tuple); castid = simple_heap_insert(relation, tuple);
CatalogUpdateIndexes(relation, tuple); CatalogUpdateIndexes(relation, tuple);
/* make dependency entries */ /* make dependency entries */
myself.classId = CastRelationId; myself.classId = CastRelationId;
myself.objectId = HeapTupleGetOid(tuple); myself.objectId = castid;
myself.objectSubId = 0; myself.objectSubId = 0;
/* dependency on source type */ /* dependency on source type */
...@@ -1765,11 +1766,10 @@ CreateCast(CreateCastStmt *stmt) ...@@ -1765,11 +1766,10 @@ CreateCast(CreateCastStmt *stmt)
} }
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new cast */ /* Post creation hook for new cast */
InvokeObjectAccessHook(OAT_POST_CREATE, InvokeObjectAccessHook(OAT_POST_CREATE, CastRelationId, castid, 0);
CastRelationId, myself.objectId, 0);
heap_freetuple(tuple); heap_freetuple(tuple);
......
...@@ -310,7 +310,7 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid) ...@@ -310,7 +310,7 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId()); recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new operator family */ /* Post creation hook for new operator family */
InvokeObjectAccessHook(OAT_POST_CREATE, InvokeObjectAccessHook(OAT_POST_CREATE,
...@@ -713,7 +713,7 @@ DefineOpClass(CreateOpClassStmt *stmt) ...@@ -713,7 +713,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId()); recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new operator class */ /* Post creation hook for new operator class */
InvokeObjectAccessHook(OAT_POST_CREATE, InvokeObjectAccessHook(OAT_POST_CREATE,
......
...@@ -388,8 +388,7 @@ create_proc_lang(const char *languageName, bool replace, ...@@ -388,8 +388,7 @@ create_proc_lang(const char *languageName, bool replace,
* Create dependencies for the new language. If we are updating an * Create dependencies for the new language. If we are updating an
* existing language, first delete any existing pg_depend entries. * existing language, first delete any existing pg_depend entries.
* (However, since we are not changing ownership or permissions, the * (However, since we are not changing ownership or permissions, the
* shared dependencies do *not* need to change, and we leave them alone. * shared dependencies do *not* need to change, and we leave them alone.)
* We also don't change any pre-existing extension-membership dependency.)
*/ */
myself.classId = LanguageRelationId; myself.classId = LanguageRelationId;
myself.objectId = HeapTupleGetOid(tup); myself.objectId = HeapTupleGetOid(tup);
...@@ -404,8 +403,7 @@ create_proc_lang(const char *languageName, bool replace, ...@@ -404,8 +403,7 @@ create_proc_lang(const char *languageName, bool replace,
languageOwner); languageOwner);
/* dependency on extension */ /* dependency on extension */
if (!is_update) recordDependencyOnCurrentExtension(&myself, is_update);
recordDependencyOnCurrentExtension(&myself);
/* dependency on the PL handler function */ /* dependency on the PL handler function */
referenced.classId = ProcedureRelationId; referenced.classId = ProcedureRelationId;
......
...@@ -142,7 +142,7 @@ makeParserDependencies(HeapTuple tuple) ...@@ -142,7 +142,7 @@ makeParserDependencies(HeapTuple tuple)
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* dependencies on functions */ /* dependencies on functions */
referenced.classId = ProcedureRelationId; referenced.classId = ProcedureRelationId;
...@@ -479,7 +479,7 @@ makeDictionaryDependencies(HeapTuple tuple) ...@@ -479,7 +479,7 @@ makeDictionaryDependencies(HeapTuple tuple)
recordDependencyOnOwner(myself.classId, myself.objectId, dict->dictowner); recordDependencyOnOwner(myself.classId, myself.objectId, dict->dictowner);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* dependency on template */ /* dependency on template */
referenced.classId = TSTemplateRelationId; referenced.classId = TSTemplateRelationId;
...@@ -1069,7 +1069,7 @@ makeTSTemplateDependencies(HeapTuple tuple) ...@@ -1069,7 +1069,7 @@ makeTSTemplateDependencies(HeapTuple tuple)
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on extension */ /* dependency on extension */
recordDependencyOnCurrentExtension(&myself); recordDependencyOnCurrentExtension(&myself, false);
/* dependencies on functions */ /* dependencies on functions */
referenced.classId = ProcedureRelationId; referenced.classId = ProcedureRelationId;
...@@ -1417,8 +1417,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld, ...@@ -1417,8 +1417,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
recordDependencyOnOwner(myself.classId, myself.objectId, cfg->cfgowner); recordDependencyOnOwner(myself.classId, myself.objectId, cfg->cfgowner);
/* dependency on extension */ /* dependency on extension */
if (!removeOld) recordDependencyOnCurrentExtension(&myself, removeOld);
recordDependencyOnCurrentExtension(&myself);
/* dependency on parser */ /* dependency on parser */
referenced.classId = TSParserRelationId; referenced.classId = TSParserRelationId;
......
...@@ -201,7 +201,8 @@ extern void recordMultipleDependencies(const ObjectAddress *depender, ...@@ -201,7 +201,8 @@ extern void recordMultipleDependencies(const ObjectAddress *depender,
int nreferenced, int nreferenced,
DependencyType behavior); DependencyType behavior);
extern void recordDependencyOnCurrentExtension(const ObjectAddress *object); extern void recordDependencyOnCurrentExtension(const ObjectAddress *object,
bool isReplace);
extern long deleteDependencyRecordsFor(Oid classId, Oid objectId, extern long deleteDependencyRecordsFor(Oid classId, Oid objectId,
bool skipExtensionDeps); bool skipExtensionDeps);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment