diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 25d24723dc0..743d91c1a11 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -180,8 +180,6 @@ static void reportDependentObjects(const ObjectAddresses *targetObjects, static void deleteOneObject(const ObjectAddress *object, Relation *depRel, int32 flags); static void doDeletion(const ObjectAddress *object, int flags); -static void AcquireDeletionLock(const ObjectAddress *object, int flags); -static void ReleaseDeletionLock(const ObjectAddress *object); static bool find_expr_references_walker(Node *node, find_expr_references_context *context); static void eliminate_duplicate_dependencies(ObjectAddresses *addrs); @@ -1291,11 +1289,14 @@ doDeletion(const ObjectAddress *object, int flags) /* * AcquireDeletionLock - acquire a suitable lock for deleting an object * + * Accepts the same flags as performDeletion (though currently only + * PERFORM_DELETION_CONCURRENTLY does anything). + * * We use LockRelation for relations, LockDatabaseObject for everything - * else. Note that dependency.c is not concerned with deleting any kind of - * shared-across-databases object, so we have no need for LockSharedObject. + * else. Shared-across-databases objects are not currently supported + * because no caller cares, but could be modified to use LockSharedObject. */ -static void +void AcquireDeletionLock(const ObjectAddress *object, int flags) { if (object->classId == RelationRelationId) @@ -1321,8 +1322,10 @@ AcquireDeletionLock(const ObjectAddress *object, int flags) /* * ReleaseDeletionLock - release an object deletion lock + * + * Companion to AcquireDeletionLock. */ -static void +void ReleaseDeletionLock(const ObjectAddress *object) { if (object->classId == RelationRelationId) diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 65ecc45d49e..02f5591afae 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -1248,7 +1248,10 @@ shdepDropOwned(List *roleids, DropBehavior behavior) sdepForm->objid); break; case SHARED_DEPENDENCY_POLICY: - /* If unable to remove role from policy, remove policy. */ + /* + * Try to remove role from policy; if unable to, remove + * policy. + */ if (!RemoveRoleFromObjectPolicy(roleid, sdepForm->classid, sdepForm->objid)) @@ -1256,6 +1259,18 @@ shdepDropOwned(List *roleids, DropBehavior behavior) obj.classId = sdepForm->classid; obj.objectId = sdepForm->objid; obj.objectSubId = sdepForm->objsubid; + /* + * Acquire lock on object, then verify this dependency + * is still relevant. If not, the object might have + * been dropped or the policy modified. Ignore the + * object in that case. + */ + AcquireDeletionLock(&obj, 0); + if (!systable_recheck_tuple(scan, tuple)) + { + ReleaseDeletionLock(&obj); + break; + } add_exact_object_address(&obj, deleteobjs); } break; @@ -1266,6 +1281,13 @@ shdepDropOwned(List *roleids, DropBehavior behavior) obj.classId = sdepForm->classid; obj.objectId = sdepForm->objid; obj.objectSubId = sdepForm->objsubid; + /* as above */ + AcquireDeletionLock(&obj, 0); + if (!systable_recheck_tuple(scan, tuple)) + { + ReleaseDeletionLock(&obj); + break; + } add_exact_object_address(&obj, deleteobjs); } break; diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 16f6719a2fe..8c403903b6d 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -172,6 +172,10 @@ typedef enum ObjectClass #define PERFORM_DELETION_INTERNAL 0x0001 #define PERFORM_DELETION_CONCURRENTLY 0x0002 +extern void AcquireDeletionLock(const ObjectAddress *object, int flags); + +extern void ReleaseDeletionLock(const ObjectAddress *object); + extern void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags);