diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index db86262b4f..eca064f0cd 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -560,17 +560,21 @@ findDependentObjects(const ObjectAddress *object, * another object, or is part of the extension that is the * other object. We have three cases: * - * 1. At the outermost recursion level, disallow the DROP. (We - * just ereport here, rather than proceeding, since no other - * dependencies are likely to be interesting.) However, if - * the owning object is listed in pendingObjects, just release - * the caller's lock and return; we'll eventually complete the - * DROP when we reach that entry in the pending list. + * 1. At the outermost recursion level, we normally disallow + * the DROP. (We just ereport here, rather than proceeding, + * since no other dependencies are likely to be interesting.) + * However, there are exceptions. */ if (stack == NULL) { char *otherObjDesc; + /* + * Exception 1a: if the owning object is listed in + * pendingObjects, just release the caller's lock and + * return. We'll eventually complete the DROP when we + * reach that entry in the pending list. + */ if (pendingObjects && object_address_present(&otherObject, pendingObjects)) { @@ -579,6 +583,21 @@ findDependentObjects(const ObjectAddress *object, ReleaseDeletionLock(object); return; } + + /* + * Exception 1b: if the owning object is the extension + * currently being created/altered, it's okay to continue + * with the deletion. This allows dropping of an + * extension's objects within the extension's scripts, + * as well as corner cases such as dropping a transient + * object created within such a script. + */ + if (creating_extension && + otherObject.classId == ExtensionRelationId && + otherObject.objectId == CurrentExtensionObject) + break; + + /* No exception applies, so throw the error */ otherObjDesc = getObjectDescription(&otherObject); ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index a8653cd495..d1d458d7fa 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -957,10 +957,12 @@ AddNewRelationType(const char *typeName, * reltablespace: OID of tablespace it goes in * relid: OID to assign to new rel, or InvalidOid to select a new OID * reltypeid: OID to assign to rel's rowtype, or InvalidOid to select one + * reloftypeid: if a typed table, OID of underlying type; else InvalidOid * ownerid: OID of new rel's owner * tupdesc: tuple descriptor (source of column definitions) * cooked_constraints: list of precooked check constraints and defaults * relkind: relkind for new rel + * relpersistence: rel's persistence status (permanent, temp, or unlogged) * shared_relation: TRUE if it's to be a shared relation * mapped_relation: TRUE if the relation will use the relfilenode map * oidislocal: TRUE if oid column (if any) should be marked attislocal @@ -1235,6 +1237,10 @@ heap_create_with_catalog(const char *relname, * should they have any ACL entries. The same applies for extension * dependencies. * + * If it's a temp table, we do not make it an extension member; this + * prevents the unintuitive result that deletion of the temp table at + * session end would make the whole extension go away. + * * Also, skip this in bootstrap mode, since we don't make dependencies * while bootstrapping. */ @@ -1255,7 +1261,8 @@ heap_create_with_catalog(const char *relname, recordDependencyOnOwner(RelationRelationId, relid, ownerid); - recordDependencyOnCurrentExtension(&myself, false); + if (relpersistence != RELPERSISTENCE_TEMP) + recordDependencyOnCurrentExtension(&myself, false); if (reloftypeid) { diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 80d6fc7d0c..dc8f8eaf3f 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -3558,7 +3558,8 @@ InitTempTableNamespace(void) * temp tables. This works because the places that access the temp * namespace for my own backend skip permissions checks on it. */ - namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); + namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID, + true); /* Advance command counter to make namespace visible */ CommandCounterIncrement(); } @@ -3582,7 +3583,8 @@ InitTempTableNamespace(void) toastspaceId = get_namespace_oid(namespaceName, true); if (!OidIsValid(toastspaceId)) { - toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID); + toastspaceId = NamespaceCreate(namespaceName, BOOTSTRAP_SUPERUSERID, + true); /* Advance command counter to make namespace visible */ CommandCounterIncrement(); } diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c index d5ab48a59d..be812a246c 100644 --- a/src/backend/catalog/pg_namespace.c +++ b/src/backend/catalog/pg_namespace.c @@ -26,10 +26,18 @@ /* ---------------- * NamespaceCreate + * + * Create a namespace (schema) with the given name and owner OID. + * + * If isTemp is true, this schema is a per-backend schema for holding + * temporary tables. Currently, the only effect of that is to prevent it + * from being linked as a member of any active extension. (If someone + * does CREATE TEMP TABLE in an extension script, we don't want the temp + * schema to become part of the extension.) * --------------- */ Oid -NamespaceCreate(const char *nspName, Oid ownerId) +NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) { Relation nspdesc; HeapTuple tup; @@ -82,8 +90,9 @@ NamespaceCreate(const char *nspName, Oid ownerId) /* dependency on owner */ recordDependencyOnOwner(NamespaceRelationId, nspoid, ownerId); - /* dependency on extension */ - recordDependencyOnCurrentExtension(&myself, false); + /* dependency on extension ... but not for magic temp schemas */ + if (!isTemp) + recordDependencyOnCurrentExtension(&myself, false); /* Post creation hook for new schema */ InvokeObjectAccessHook(OAT_POST_CREATE, NamespaceRelationId, nspoid, 0); diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 916328529a..6745af501d 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -94,7 +94,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) save_sec_context | SECURITY_LOCAL_USERID_CHANGE); /* Create the schema's namespace */ - namespaceId = NamespaceCreate(schemaName, owner_uid); + namespaceId = NamespaceCreate(schemaName, owner_uid, false); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); diff --git a/src/include/catalog/pg_namespace.h b/src/include/catalog/pg_namespace.h index aad76a1452..1daba477b4 100644 --- a/src/include/catalog/pg_namespace.h +++ b/src/include/catalog/pg_namespace.h @@ -79,6 +79,6 @@ DESCR("standard public schema"); /* * prototypes for functions in pg_namespace.c */ -extern Oid NamespaceCreate(const char *nspName, Oid ownerId); +extern Oid NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp); #endif /* PG_NAMESPACE_H */