diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index 740570c566..f4e0663ad5 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -2989,44 +2989,81 @@ CheckSetNamespace(Oid oldNspOid, Oid nspOid) * * Note: calling this may result in a CommandCounterIncrement operation, * if we have to create or clean out the temp namespace. + * + * This function acquires AccessShareLock on the target + * namespace. Without this, the namespace could be dropped before our + * transaction commits, leaving behind objects with relnamespace pointing + * to a no-longer-existent namespace. */ Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p) { char *schemaname; Oid namespaceId; + Oid oldnspid = InvalidOid; + bool retry = false; + uint64 inval_count; /* deconstruct the name list */ DeconstructQualifiedName(names, &schemaname, objname_p); - if (schemaname) + for (;;) { - /* check for pg_temp alias */ - if (strcmp(schemaname, "pg_temp") == 0) + inval_count = SharedInvalidMessageCounter; + + if (schemaname) { - /* Initialize temp namespace */ - AccessTempTableNamespace(false); - return myTempNamespace; + /* check for pg_temp alias */ + if (strcmp(schemaname, "pg_temp") == 0) + { + /* Initialize temp namespace */ + AccessTempTableNamespace(false); + return myTempNamespace; + } + /* use exact schema given */ + namespaceId = get_namespace_oid(schemaname, false); + /* we do not check for USAGE rights here! */ } - /* use exact schema given */ - namespaceId = get_namespace_oid(schemaname, false); - /* we do not check for USAGE rights here! */ - } - else - { - /* use the default creation namespace */ - recomputeNamespacePath(); - if (activeTempCreationPending) + else { - /* Need to initialize temp namespace */ - AccessTempTableNamespace(true); - return myTempNamespace; + /* use the default creation namespace */ + recomputeNamespacePath(); + if (activeTempCreationPending) + { + /* Need to initialize temp namespace */ + AccessTempTableNamespace(true); + return myTempNamespace; + } + namespaceId = activeCreationNamespace; + if (!OidIsValid(namespaceId)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("no schema has been selected to create in"))); } - namespaceId = activeCreationNamespace; - if (!OidIsValid(namespaceId)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_SCHEMA), - errmsg("no schema has been selected to create in"))); + + if (retry) + { + /* If nothing changed, we're done. */ + if (namespaceId == oldnspid) + break; + + /* If creation namespace has changed, give up old lock. */ + if (namespaceId != oldnspid) + UnlockDatabaseObject(NamespaceRelationId, oldnspid, 0, + AccessShareLock); + } + + /* Lock namespace. */ + if (namespaceId != oldnspid) + LockDatabaseObject(NamespaceRelationId, namespaceId, 0, AccessShareLock); + + /* If no invalidation message were processed, we're done! */ + if (inval_count == SharedInvalidMessageCounter) + break; + + /* Something may have changed, so recheck our work. */ + retry = true; + oldnspid = namespaceId; } return namespaceId;