On Mon, Jun 3, 2024 at 12:14 PM jian he <jian.universal...@gmail.com> wrote: > > hi. > > ---- setup > drop table if exist test__int cascade; > create extension intarray; > > CREATE TABLE test__int( a int[] ); > CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = > 1)); > drop extension intarray cascade; > NOTICE: drop cascades to index text_idx > 2024-06-03 11:53:32.629 CST [41165] ERROR: cache lookup failed for > function 17758 > 2024-06-03 11:53:32.629 CST [41165] STATEMENT: drop extension intarray > cascade; > ERROR: cache lookup failed for function 17758 > > ------------------------------------------------ > backtrace info: > index_getprocinfo > #0 index_opclass_options (indrel=0x7faeca727b58, attnum=1, > attoptions=94372901674408, validate=false) > at > ../../Desktop/pg_src/src4/postgres/src/backend/access/index/indexam.c:1034 > #1 0x000055d4e63a79cb in RelationGetIndexAttOptions > (relation=0x7faeca727b58, copy=false) > at > ../../Desktop/pg_src/src4/postgres/src/backend/utils/cache/relcache.c:5872 > #2 0x000055d4e639d72d in RelationInitIndexAccessInfo > (relation=0x7faeca727b58) > at > ../../Desktop/pg_src/src4/postgres/src/backend/utils/cache/relcache.c:1569 > #3 0x000055d4e639c5ac in RelationBuildDesc (targetRelId=24582, insertIt=true) > at > ../../Desktop/pg_src/src4/postgres/src/backend/utils/cache/relcache.c:1207 > #4 0x000055d4e639e9ce in RelationIdGetRelation (relationId=24582) > at > ../../Desktop/pg_src/src4/postgres/src/backend/utils/cache/relcache.c:2115 > #5 0x000055d4e5a412fd in relation_open (relationId=24582, lockmode=8) > at > ../../Desktop/pg_src/src4/postgres/src/backend/access/common/relation.c:58 > #6 0x000055d4e5ae6a06 in index_open (relationId=24582, lockmode=8) > at > ../../Desktop/pg_src/src4/postgres/src/backend/access/index/indexam.c:137 > #7 0x000055d4e5be61b8 in index_drop (indexId=24582, concurrent=false, > concurrent_lock_mode=false) > at ../../Desktop/pg_src/src4/postgres/src/backend/catalog/index.c:2156 > ------------------------ > i guess it's because we first dropped the function g_intbig_options
in this context, the index "text_idx" has a normal dependency with pg_opclass. but `drop extension intarray cascade;`, CASCADE means that we drop the pg_opclass and pg_opclass's inner dependency first, then drop the index. while drop index (sub functions RelationGetIndexAttOptions,index_opclass_options, index_getprocinfo) requires that pg_opclass and its inner dependencies (namely g_intbig_options, g_int_options) are not dropped first. in deleteObjectsInList, under certain conditions trying to sort the to be deleted object list by just using sort_object_addresses seems to work, but it looks like a hack. maybe the proper fix would be in findDependentObjects.
From 8deefb638df270cf26e5649b1a99f218474821fa Mon Sep 17 00:00:00 2001 From: jian he <jian.universality@gmail.com> Date: Fri, 7 Jun 2024 11:25:03 +0800 Subject: [PATCH v1 1/1] trying to resolve drop extension deletion order sometimes, drop extension cascade cannot resolve the internal deletion order correctly. e.g. drop table if exist test__int cascade; create extension intarray; CREATE TABLE test__int( a int[] ); CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = 1)); drop extension intarray cascade; ---- the index "text_idx" only have a normal dependency with pg_opclass. even though the index can be dropped separately without affecting the "pg_opclass". but CASCADE means that we drop the pg_opclass and pg_opclass's inner dependency first, then drop the index. while drop index (sub functions RelationGetIndexAttOptions,index_opclass_options, index_getprocinfo) requires that pg_opclass and its inner dependencies are not dropped first. Resorting the deleted objects in deleteObjectsInList using sort_object_addresses seems like a hack. but it works for now. discussion: https://www.postgresql.org/message-id/CACJufxEspPKC7oxVLci7oUddUmcAGNKJnWWSD7-B03bGtT9gDg%40mail.gmail.com --- src/backend/catalog/dependency.c | 33 +++++++++++++++++++++++++++---- src/backend/catalog/pg_shdepend.c | 2 +- src/backend/commands/dropcmds.c | 2 +- src/backend/commands/indexcmds.c | 2 +- src/backend/commands/tablecmds.c | 13 +++++++----- src/include/catalog/dependency.h | 2 +- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index d4b5b2ad..d0c2454b 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -183,7 +183,7 @@ static void DeleteInitPrivs(const ObjectAddress *object); */ static void deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, - int flags) + int flags, bool sort_objects) { int i; @@ -213,6 +213,8 @@ deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, } } + if (sort_objects) + sort_object_addresses(targetObjects); /* * Delete all the objects in the proper order, except that if told to, we * should skip the original object(s). @@ -311,7 +313,7 @@ performDeletion(const ObjectAddress *object, object); /* do the deed */ - deleteObjectsInList(targetObjects, &depRel, flags); + deleteObjectsInList(targetObjects, &depRel, flags, false); /* And clean up */ free_object_addresses(targetObjects); @@ -330,16 +332,39 @@ performDeletion(const ObjectAddress *object, */ void performMultipleDeletions(const ObjectAddresses *objects, - DropBehavior behavior, int flags) + DropBehavior behavior, int flags, bool sortable) { Relation depRel; ObjectAddresses *targetObjects; int i; + bool sort_objects = true; + char relkind = '\0'; /* No work if no objects... */ if (objects->numrefs <= 0) return; + for (int j = 0; j < objects->numrefs; j++) + { + const ObjectAddress *thisobj = objects->refs + j; + if (thisobj->classId != RelationRelationId) + continue; + relkind = get_rel_relkind(thisobj->objectId); + + /* + * for partitioned table, sequence findDependentObjects can resolve + * the delete objects order correctly, othercase, we can sort the + * to be deleted objects via sort_object_addresses in deleteObjectsInList + */ + if (relkind == RELKIND_PARTITIONED_TABLE || relkind == RELKIND_SEQUENCE) + { + sort_objects = false; + break; + } + } + + if (!(sortable && sort_objects)) + sort_objects = false; /* * We save some cycles by opening pg_depend just once and passing the * Relation pointer down to all the recursive deletion steps. @@ -387,7 +412,7 @@ performMultipleDeletions(const ObjectAddresses *objects, (objects->numrefs == 1 ? objects->refs : NULL)); /* do the deed */ - deleteObjectsInList(targetObjects, &depRel, flags); + deleteObjectsInList(targetObjects, &depRel, flags, sort_objects); /* And clean up */ free_object_addresses(targetObjects); diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 20bcfd77..8aef6596 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -1498,7 +1498,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior) sort_object_addresses(deleteobjs); /* the dependency mechanism does the actual work */ - performMultipleDeletions(deleteobjs, behavior, 0); + performMultipleDeletions(deleteobjs, behavior, 0, true); table_close(sdepRel, RowExclusiveLock); diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 85eec7e3..7aadd71b 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -120,7 +120,7 @@ RemoveObjects(DropStmt *stmt) } /* Here we really delete them. */ - performMultipleDeletions(objects, stmt->behavior, 0); + performMultipleDeletions(objects, stmt->behavior, 0, true); free_object_addresses(objects); } diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 309389e2..d70a112a 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -4209,7 +4209,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein * right lock level. */ performMultipleDeletions(objects, DROP_RESTRICT, - PERFORM_DELETION_CONCURRENT_LOCK | PERFORM_DELETION_INTERNAL); + PERFORM_DELETION_CONCURRENT_LOCK | PERFORM_DELETION_INTERNAL, true); } PopActiveSnapshot(); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 7b6c69b7..ab005cc2 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1459,6 +1459,7 @@ RemoveRelations(DropStmt *drop) ListCell *cell; int flags = 0; LOCKMODE lockmode = AccessExclusiveLock; + bool sortable = true; /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */ if (drop->concurrent) @@ -1604,7 +1605,9 @@ RemoveRelations(DropStmt *drop) add_exact_object_address(&obj, objects); } - performMultipleDeletions(objects, drop->behavior, flags); + if (list_length(drop->objects) > 1) + sortable = false; + performMultipleDeletions(objects, drop->behavior, flags, sortable); free_object_addresses(objects); } @@ -9100,7 +9103,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, if (!recursing) { /* Recursion has ended, drop everything that was collected */ - performMultipleDeletions(addrs, behavior, 0); + performMultipleDeletions(addrs, behavior, 0, true); free_object_addresses(addrs); } @@ -13812,7 +13815,7 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) * It should be okay to use DROP_RESTRICT here, since nothing else should * be depending on these objects. */ - performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); + performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL, true); free_object_addresses(objects); @@ -17448,7 +17451,7 @@ PreCommit_on_commit_actions(void) * by the user, we pass the PERFORM_DELETION_INTERNAL flag. */ performMultipleDeletions(targetObjects, DROP_CASCADE, - PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY); + PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY, true); PopActiveSnapshot(); @@ -19488,7 +19491,7 @@ DropClonedTriggersFromPartition(Oid partitionId) /* make the dependency removal visible to the deletion below */ CommandCounterIncrement(); - performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL); + performMultipleDeletions(objects, DROP_RESTRICT, PERFORM_DELETION_INTERNAL, true); /* done */ free_object_addresses(objects); diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 7eee66f8..f9739f87 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -108,7 +108,7 @@ extern void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags); extern void performMultipleDeletions(const ObjectAddresses *objects, - DropBehavior behavior, int flags); + DropBehavior behavior, int flags, bool sortable); extern void recordDependencyOnExpr(const ObjectAddress *depender, Node *expr, List *rtable, -- 2.34.1