From 96d2e0de87ee03a37aa0532484c75a370802bbe3 Mon Sep 17 00:00:00 2001 From: jian he Date: Wed, 11 Jun 2025 21:11:55 +0800 Subject: [PATCH v43 1/1] check if we can drop merging partition before actually did it. --- src/backend/catalog/dependency.c | 51 ++++++++++++++++++++++++++++++++ src/backend/commands/tablecmds.c | 21 +++++++++++++ src/include/catalog/dependency.h | 2 ++ 3 files changed, 74 insertions(+) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 18316a3968b..add706b9f85 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -319,6 +319,57 @@ performDeletion(const ObjectAddress *object, table_close(depRel, RowExclusiveLock); } + +/* + * performDeletionCheck: Check whether a specific object can be safely deleted. + * This function does not perform any deletion; instead, it raises an error + * if the object cannot be deleted due to existing dependencies. + * + * It can be useful when you need delete some objects later. See comments in + * performDeletion too. + * The behavior must specified as DROP_RESTRICT. + */ +void +performDeletionCheck(const ObjectAddress *object, + DropBehavior behavior, int flags) +{ + Relation depRel; + ObjectAddresses *targetObjects; + + Assert(behavior == DROP_RESTRICT); + + depRel = table_open(DependRelationId, RowExclusiveLock); + + AcquireDeletionLock(object, 0); + + /* + * Construct a list of objects we want delete later (ie, the given object plus + * everything directly or indirectly dependent on it). + */ + targetObjects = new_object_addresses(); + + findDependentObjects(object, + DEPFLAG_ORIGINAL, + flags, + NULL, /* empty stack */ + targetObjects, + NULL, /* no pendingObjects */ + &depRel); + + /* + * Check if deletion is allowed. + */ + reportDependentObjects(targetObjects, + behavior, + flags, + object); + + /* And clean up */ + free_object_addresses(targetObjects); + + table_close(depRel, RowExclusiveLock); +} + /* * performMultipleDeletions: Similar to performDeletion, but act on multiple * objects at once. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index d6ce87dd965..552db167854 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -22603,6 +22603,27 @@ ATExecMergePartitions(List **wqueue, AlteredTableInfo *tab, Relation rel, Assert(OidIsValid(ownerId)); newPartRel = createPartitionTable(cmd->name, rel, ownerId); + /* + * Perform a preliminary check to determine whether it's safe to drop all + * merging partitions before we actually do so later. After merging rows + * into the new partitions via moveMergedTablesRows, all old partitions need + * be dropped. However, since the drop behavior is DROP_RESTRICT and the + * merge process (moveMergedTablesRows) can be time-consuming, performing an + * early check on the drop eligibility of old partitions is preferable. + */ + foreach(listptr, mergingPartitionsList) + { + ObjectAddress object; + Relation mergingPartition = (Relation) lfirst(listptr); + + /* Get oid of the later to be dropped relation */ + object.objectId = RelationGetRelid(mergingPartition); + object.classId = RelationRelationId; + object.objectSubId = 0; + + performDeletionCheck(&object, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); + } + /* * Switch to the table owner's userid, so that any index functions are run * as that user. Also lock down security-restricted operations and diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 0ea7ccf5243..f54233499bf 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -107,6 +107,8 @@ extern void ReleaseDeletionLock(const ObjectAddress *object); extern void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags); +extern void performDeletionCheck(const ObjectAddress *object, + DropBehavior behavior, int flags); extern void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags); -- 2.34.1