diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 13a1a35c65..7007e83873 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.58 2006/07/14 14:52:17 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.59 2006/08/20 21:56:16 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -57,17 +57,18 @@ /* expansible list of ObjectAddresses */ -typedef struct +struct ObjectAddresses { ObjectAddress *refs; /* => palloc'd array */ int numrefs; /* current number of references */ int maxrefs; /* current size of palloc'd array */ -} ObjectAddresses; +}; +/* typedef ObjectAddresses appears in dependency.h */ /* for find_expr_references_walker */ typedef struct { - ObjectAddresses addrs; /* addresses being accumulated */ + ObjectAddresses *addrs; /* addresses being accumulated */ List *rtables; /* list of rangetables to resolve Vars */ } find_expr_references_context; @@ -92,15 +93,20 @@ static const Oid object_classes[MAX_OCLASS] = { }; +static void performDeletionWithList(const ObjectAddress *object, + ObjectAddresses *oktodelete, + DropBehavior behavior, + ObjectAddresses *alreadyDeleted); static void findAutoDeletableObjects(const ObjectAddress *object, ObjectAddresses *oktodelete, - Relation depRel); + Relation depRel, bool addself); static bool recursiveDeletion(const ObjectAddress *object, DropBehavior behavior, int msglevel, const ObjectAddress *callingObject, ObjectAddresses *oktodelete, - Relation depRel); + Relation depRel, + ObjectAddresses *alreadyDeleted); static bool deleteDependentObjects(const ObjectAddress *object, const char *objDescription, DropBehavior behavior, @@ -112,14 +118,8 @@ static bool find_expr_references_walker(Node *node, find_expr_references_context *context); static void eliminate_duplicate_dependencies(ObjectAddresses *addrs); static int object_address_comparator(const void *a, const void *b); -static void init_object_addresses(ObjectAddresses *addrs); static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId, ObjectAddresses *addrs); -static void add_exact_object_address(const ObjectAddress *object, - ObjectAddresses *addrs); -static bool object_address_present(const ObjectAddress *object, - ObjectAddresses *addrs); -static void term_object_addresses(ObjectAddresses *addrs); static void getRelationDescription(StringInfo buffer, Oid relid); @@ -139,7 +139,7 @@ performDeletion(const ObjectAddress *object, { char *objDescription; Relation depRel; - ObjectAddresses oktodelete; + ObjectAddresses *oktodelete; /* * Get object description for possible use in failure message. Must do @@ -159,19 +159,19 @@ performDeletion(const ObjectAddress *object, * even if the actual deletion pass first reaches one of them via a * non-auto dependency. */ - init_object_addresses(&oktodelete); + oktodelete = new_object_addresses(); - findAutoDeletableObjects(object, &oktodelete, depRel); + findAutoDeletableObjects(object, oktodelete, depRel, true); if (!recursiveDeletion(object, behavior, NOTICE, - NULL, &oktodelete, depRel)) + NULL, oktodelete, depRel, NULL)) ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), errmsg("cannot drop %s because other objects depend on it", objDescription), errhint("Use DROP ... CASCADE to drop the dependent objects too."))); - term_object_addresses(&oktodelete); + free_object_addresses(oktodelete); heap_close(depRel, RowExclusiveLock); @@ -179,6 +179,132 @@ performDeletion(const ObjectAddress *object, } +/* + * performDeletionWithList: As above, but the oktodelete list may have already + * filled with some objects. Also, the deleted objects are saved in the + * alreadyDeleted list. + * + * XXX performDeletion could be refactored to be a thin wrapper to this + * function. + */ +static void +performDeletionWithList(const ObjectAddress *object, + ObjectAddresses *oktodelete, + DropBehavior behavior, + ObjectAddresses *alreadyDeleted) +{ + char *objDescription; + Relation depRel; + + /* + * Get object description for possible use in failure message. Must do + * this before deleting it ... + */ + objDescription = getObjectDescription(object); + + /* + * We save some cycles by opening pg_depend just once and passing the + * Relation pointer down to all the recursive deletion steps. + */ + depRel = heap_open(DependRelationId, RowExclusiveLock); + + /* + * Construct a list of objects that are reachable by AUTO or INTERNAL + * dependencies from the target object. These should be deleted silently, + * even if the actual deletion pass first reaches one of them via a + * non-auto dependency. + */ + findAutoDeletableObjects(object, oktodelete, depRel, true); + + if (!recursiveDeletion(object, behavior, NOTICE, + NULL, oktodelete, depRel, alreadyDeleted)) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("cannot drop %s because other objects depend on it", + objDescription), + errhint("Use DROP ... CASCADE to drop the dependent objects too."))); + + heap_close(depRel, RowExclusiveLock); + + pfree(objDescription); +} + +/* + * performMultipleDeletion: Similar to performDeletion, but act on multiple + * objects at once. + * + * The main difference from issuing multiple performDeletion calls is that the + * list of objects that would be implicitly dropped, for each object to be + * dropped, is the union of the implicit-object list for all objects. This + * makes each check be more relaxed. + */ +void +performMultipleDeletions(const ObjectAddresses *objects, + DropBehavior behavior) +{ + ObjectAddresses *implicit; + ObjectAddresses *alreadyDeleted; + Relation depRel; + int i; + + implicit = new_object_addresses(); + alreadyDeleted = new_object_addresses(); + + depRel = heap_open(DependRelationId, RowExclusiveLock); + + /* + * Get the list of all objects that would be deleted after deleting the + * whole "objects" list. We do this by creating a list of all implicit + * (INTERNAL and AUTO) dependencies for each object we collected above. + * Note that we must exclude the objects themselves from this list! + */ + for (i = 0; i < objects->numrefs; i++) + { + ObjectAddress obj = objects->refs[i]; + + /* + * If it's in the implicit list, we don't need to delete it explicitly + * nor follow the dependencies, because that was already done in a + * previous iteration. + */ + if (object_address_present(&obj, implicit)) + continue; + + /* + * Add the objects dependent on this one to the global list of implicit + * objects. + */ + findAutoDeletableObjects(&obj, implicit, depRel, false); + } + + /* Do the deletion. */ + for (i = 0; i < objects->numrefs; i++) + { + ObjectAddress obj = objects->refs[i]; + + /* + * Skip this object if it was already deleted in a previous iteration. + */ + if (object_address_present(&obj, alreadyDeleted)) + continue; + + /* + * Skip this object if it's also present in the list of implicit + * objects --- it will be deleted later. + */ + if (object_address_present(&obj, implicit)) + continue; + + /* delete it */ + performDeletionWithList(&obj, implicit, behavior, alreadyDeleted); + } + + heap_close(depRel, RowExclusiveLock); + + free_object_addresses(implicit); + free_object_addresses(alreadyDeleted); +} + /* * deleteWhatDependsOn: attempt to drop everything that depends on the * specified object, though not the object itself. Behavior is always @@ -194,7 +320,7 @@ deleteWhatDependsOn(const ObjectAddress *object, { char *objDescription; Relation depRel; - ObjectAddresses oktodelete; + ObjectAddresses *oktodelete; /* * Get object description for possible use in failure messages @@ -213,9 +339,9 @@ deleteWhatDependsOn(const ObjectAddress *object, * even if the actual deletion pass first reaches one of them via a * non-auto dependency. */ - init_object_addresses(&oktodelete); + oktodelete = new_object_addresses(); - findAutoDeletableObjects(object, &oktodelete, depRel); + findAutoDeletableObjects(object, oktodelete, depRel, true); /* * Now invoke only step 2 of recursiveDeletion: just recurse to the stuff @@ -224,7 +350,7 @@ deleteWhatDependsOn(const ObjectAddress *object, if (!deleteDependentObjects(object, objDescription, DROP_CASCADE, showNotices ? NOTICE : DEBUG2, - &oktodelete, depRel)) + oktodelete, depRel)) ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), errmsg("failed to drop all objects depending on %s", @@ -235,7 +361,7 @@ deleteWhatDependsOn(const ObjectAddress *object, * anything then each recursive call will have ended with one. */ - term_object_addresses(&oktodelete); + free_object_addresses(oktodelete); heap_close(depRel, RowExclusiveLock); @@ -246,15 +372,15 @@ deleteWhatDependsOn(const ObjectAddress *object, /* * findAutoDeletableObjects: find all objects that are reachable by AUTO or * INTERNAL dependency paths from the given object. Add them all to the - * oktodelete list. Note that the originally given object will also be - * added to the list. + * oktodelete list. If addself is true, the originally given object will also + * be added to the list. * * depRel is the already-open pg_depend relation. */ static void findAutoDeletableObjects(const ObjectAddress *object, ObjectAddresses *oktodelete, - Relation depRel) + Relation depRel, bool addself) { ScanKeyData key[3]; int nkeys; @@ -269,7 +395,8 @@ findAutoDeletableObjects(const ObjectAddress *object, */ if (object_address_present(object, oktodelete)) return; - add_exact_object_address(object, oktodelete); + if (addself) + add_exact_object_address(object, oktodelete); /* * Scan pg_depend records that link to this object, showing the things @@ -316,7 +443,7 @@ findAutoDeletableObjects(const ObjectAddress *object, otherObject.classId = foundDep->classid; otherObject.objectId = foundDep->objid; otherObject.objectSubId = foundDep->objsubid; - findAutoDeletableObjects(&otherObject, oktodelete, depRel); + findAutoDeletableObjects(&otherObject, oktodelete, depRel, true); break; case DEPENDENCY_PIN: @@ -387,7 +514,8 @@ recursiveDeletion(const ObjectAddress *object, int msglevel, const ObjectAddress *callingObject, ObjectAddresses *oktodelete, - Relation depRel) + Relation depRel, + ObjectAddresses *alreadyDeleted) { bool ok = true; char *objDescription; @@ -553,7 +681,7 @@ recursiveDeletion(const ObjectAddress *object, getObjectDescription(&owningObject)))); if (!recursiveDeletion(&owningObject, behavior, msglevel, - object, oktodelete, depRel)) + object, oktodelete, depRel, alreadyDeleted)) ok = false; pfree(objDescription); @@ -579,9 +707,15 @@ recursiveDeletion(const ObjectAddress *object, */ /* - * Step 3: delete the object itself. + * Step 3: delete the object itself, and save it to the list of + * deleted objects if appropiate. */ doDeletion(object); + if (alreadyDeleted != NULL) + { + if (!object_address_present(object, alreadyDeleted)) + add_exact_object_address(object, alreadyDeleted); + } /* * Delete any comments associated with this object. (This is a convenient @@ -712,7 +846,7 @@ deleteDependentObjects(const ObjectAddress *object, getObjectDescription(&otherObject)))); if (!recursiveDeletion(&otherObject, behavior, msglevel, - object, oktodelete, depRel)) + object, oktodelete, depRel, NULL)) ok = false; break; case DEPENDENCY_AUTO: @@ -728,7 +862,7 @@ deleteDependentObjects(const ObjectAddress *object, getObjectDescription(&otherObject)))); if (!recursiveDeletion(&otherObject, behavior, msglevel, - object, oktodelete, depRel)) + object, oktodelete, depRel, NULL)) ok = false; break; case DEPENDENCY_PIN: @@ -858,7 +992,7 @@ recordDependencyOnExpr(const ObjectAddress *depender, { find_expr_references_context context; - init_object_addresses(&context.addrs); + context.addrs = new_object_addresses(); /* Set up interpretation for Vars at varlevelsup = 0 */ context.rtables = list_make1(rtable); @@ -867,14 +1001,14 @@ recordDependencyOnExpr(const ObjectAddress *depender, find_expr_references_walker(expr, &context); /* Remove any duplicates */ - eliminate_duplicate_dependencies(&context.addrs); + eliminate_duplicate_dependencies(context.addrs); /* And record 'em */ recordMultipleDependencies(depender, - context.addrs.refs, context.addrs.numrefs, + context.addrs->refs, context.addrs->numrefs, behavior); - term_object_addresses(&context.addrs); + free_object_addresses(context.addrs); } /* @@ -895,7 +1029,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender, find_expr_references_context context; RangeTblEntry rte; - init_object_addresses(&context.addrs); + context.addrs = new_object_addresses(); /* We gin up a rather bogus rangetable list to handle Vars */ MemSet(&rte, 0, sizeof(rte)); @@ -909,30 +1043,30 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender, find_expr_references_walker(expr, &context); /* Remove any duplicates */ - eliminate_duplicate_dependencies(&context.addrs); + eliminate_duplicate_dependencies(context.addrs); /* Separate self-dependencies if necessary */ - if (behavior != self_behavior && context.addrs.numrefs > 0) + if (behavior != self_behavior && context.addrs->numrefs > 0) { - ObjectAddresses self_addrs; + ObjectAddresses *self_addrs; ObjectAddress *outobj; int oldref, outrefs; - init_object_addresses(&self_addrs); + self_addrs = new_object_addresses(); - outobj = context.addrs.refs; + outobj = context.addrs->refs; outrefs = 0; - for (oldref = 0; oldref < context.addrs.numrefs; oldref++) + for (oldref = 0; oldref < context.addrs->numrefs; oldref++) { - ObjectAddress *thisobj = context.addrs.refs + oldref; + ObjectAddress *thisobj = context.addrs->refs + oldref; if (thisobj->classId == RelationRelationId && thisobj->objectId == relId) { /* Move this ref into self_addrs */ add_object_address(OCLASS_CLASS, relId, thisobj->objectSubId, - &self_addrs); + self_addrs); } else { @@ -944,22 +1078,22 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender, outrefs++; } } - context.addrs.numrefs = outrefs; + context.addrs->numrefs = outrefs; /* Record the self-dependencies */ recordMultipleDependencies(depender, - self_addrs.refs, self_addrs.numrefs, + self_addrs->refs, self_addrs->numrefs, self_behavior); - term_object_addresses(&self_addrs); + free_object_addresses(self_addrs); } /* Record the external dependencies */ recordMultipleDependencies(depender, - context.addrs.refs, context.addrs.numrefs, + context.addrs->refs, context.addrs->numrefs, behavior); - term_object_addresses(&context.addrs); + free_object_addresses(context.addrs); } /* @@ -1008,7 +1142,7 @@ find_expr_references_walker(Node *node, { /* If it's a plain relation, reference this column */ add_object_address(OCLASS_CLASS, rte->relid, var->varattno, - &context->addrs); + context->addrs); } else if (rte->rtekind == RTE_JOIN) { @@ -1037,7 +1171,7 @@ find_expr_references_walker(Node *node, /* A constant must depend on the constant's datatype */ add_object_address(OCLASS_TYPE, con->consttype, 0, - &context->addrs); + context->addrs); /* * If it's a regclass or similar literal referring to an existing @@ -1056,7 +1190,7 @@ find_expr_references_walker(Node *node, ObjectIdGetDatum(objoid), 0, 0, 0)) add_object_address(OCLASS_PROC, objoid, 0, - &context->addrs); + context->addrs); break; case REGOPEROID: case REGOPERATOROID: @@ -1065,7 +1199,7 @@ find_expr_references_walker(Node *node, ObjectIdGetDatum(objoid), 0, 0, 0)) add_object_address(OCLASS_OPERATOR, objoid, 0, - &context->addrs); + context->addrs); break; case REGCLASSOID: objoid = DatumGetObjectId(con->constvalue); @@ -1073,7 +1207,7 @@ find_expr_references_walker(Node *node, ObjectIdGetDatum(objoid), 0, 0, 0)) add_object_address(OCLASS_CLASS, objoid, 0, - &context->addrs); + context->addrs); break; case REGTYPEOID: objoid = DatumGetObjectId(con->constvalue); @@ -1081,7 +1215,7 @@ find_expr_references_walker(Node *node, ObjectIdGetDatum(objoid), 0, 0, 0)) add_object_address(OCLASS_TYPE, objoid, 0, - &context->addrs); + context->addrs); break; } } @@ -1093,14 +1227,14 @@ find_expr_references_walker(Node *node, /* A parameter must depend on the parameter's datatype */ add_object_address(OCLASS_TYPE, param->paramtype, 0, - &context->addrs); + context->addrs); } if (IsA(node, FuncExpr)) { FuncExpr *funcexpr = (FuncExpr *) node; add_object_address(OCLASS_PROC, funcexpr->funcid, 0, - &context->addrs); + context->addrs); /* fall through to examine arguments */ } if (IsA(node, OpExpr)) @@ -1108,7 +1242,7 @@ find_expr_references_walker(Node *node, OpExpr *opexpr = (OpExpr *) node; add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, - &context->addrs); + context->addrs); /* fall through to examine arguments */ } if (IsA(node, DistinctExpr)) @@ -1116,7 +1250,7 @@ find_expr_references_walker(Node *node, DistinctExpr *distinctexpr = (DistinctExpr *) node; add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0, - &context->addrs); + context->addrs); /* fall through to examine arguments */ } if (IsA(node, ScalarArrayOpExpr)) @@ -1124,7 +1258,7 @@ find_expr_references_walker(Node *node, ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, - &context->addrs); + context->addrs); /* fall through to examine arguments */ } if (IsA(node, NullIfExpr)) @@ -1132,7 +1266,7 @@ find_expr_references_walker(Node *node, NullIfExpr *nullifexpr = (NullIfExpr *) node; add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0, - &context->addrs); + context->addrs); /* fall through to examine arguments */ } if (IsA(node, Aggref)) @@ -1140,7 +1274,7 @@ find_expr_references_walker(Node *node, Aggref *aggref = (Aggref *) node; add_object_address(OCLASS_PROC, aggref->aggfnoid, 0, - &context->addrs); + context->addrs); /* fall through to examine arguments */ } if (is_subplan(node)) @@ -1154,7 +1288,7 @@ find_expr_references_walker(Node *node, /* since there is no function dependency, need to depend on type */ add_object_address(OCLASS_TYPE, relab->resulttype, 0, - &context->addrs); + context->addrs); } if (IsA(node, ConvertRowtypeExpr)) { @@ -1162,14 +1296,14 @@ find_expr_references_walker(Node *node, /* since there is no function dependency, need to depend on type */ add_object_address(OCLASS_TYPE, cvt->resulttype, 0, - &context->addrs); + context->addrs); } if (IsA(node, RowExpr)) { RowExpr *rowexpr = (RowExpr *) node; add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0, - &context->addrs); + context->addrs); } if (IsA(node, RowCompareExpr)) { @@ -1179,12 +1313,12 @@ find_expr_references_walker(Node *node, foreach(l, rcexpr->opnos) { add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0, - &context->addrs); + context->addrs); } foreach(l, rcexpr->opclasses) { add_object_address(OCLASS_OPCLASS, lfirst_oid(l), 0, - &context->addrs); + context->addrs); } /* fall through to examine arguments */ } @@ -1193,7 +1327,7 @@ find_expr_references_walker(Node *node, CoerceToDomain *cd = (CoerceToDomain *) node; add_object_address(OCLASS_TYPE, cd->resulttype, 0, - &context->addrs); + context->addrs); } if (IsA(node, Query)) { @@ -1218,13 +1352,13 @@ find_expr_references_walker(Node *node, { case RTE_RELATION: add_object_address(OCLASS_CLASS, rte->relid, 0, - &context->addrs); + context->addrs); break; case RTE_FUNCTION: foreach(ct, rte->funccoltypes) { add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0, - &context->addrs); + context->addrs); } break; default: @@ -1332,16 +1466,21 @@ object_address_comparator(const void *a, const void *b) /* * Routines for handling an expansible array of ObjectAddress items. * - * init_object_addresses: initialize an ObjectAddresses array. + * new_object_addresses: create a new ObjectAddresses array. */ -static void -init_object_addresses(ObjectAddresses *addrs) +ObjectAddresses * +new_object_addresses(void) { - /* Initialize array to empty */ + ObjectAddresses *addrs; + + addrs = palloc(sizeof(ObjectAddresses)); + addrs->numrefs = 0; - addrs->maxrefs = 32; /* arbitrary initial array size */ + addrs->maxrefs = 32; addrs->refs = (ObjectAddress *) palloc(addrs->maxrefs * sizeof(ObjectAddress)); + + return addrs; } /* @@ -1376,7 +1515,7 @@ add_object_address(ObjectClass oclass, Oid objectId, int32 subId, * * As above, but specify entry exactly. */ -static void +void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs) { @@ -1400,7 +1539,7 @@ add_exact_object_address(const ObjectAddress *object, * * We return "true" if object is a subobject of something in the array, too. */ -static bool +bool object_address_present(const ObjectAddress *object, ObjectAddresses *addrs) { @@ -1425,10 +1564,11 @@ object_address_present(const ObjectAddress *object, /* * Clean up when done with an ObjectAddresses array. */ -static void -term_object_addresses(ObjectAddresses *addrs) +void +free_object_addresses(ObjectAddresses *addrs) { pfree(addrs->refs); + pfree(addrs); } /* diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index a0580a6bd8..31f1f654de 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.12 2006/07/14 14:52:18 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.13 2006/08/20 21:56:16 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -1061,6 +1061,9 @@ shdepDropOwned(List *roleids, DropBehavior behavior) { Relation sdepRel; ListCell *cell; + ObjectAddresses *deleteobjs; + + deleteobjs = new_object_addresses(); sdepRel = heap_open(SharedDependRelationId, AccessExclusiveLock); @@ -1105,6 +1108,9 @@ shdepDropOwned(List *roleids, DropBehavior behavior) while ((tuple = systable_getnext(scan)) != NULL) { + ObjectAddress obj; + GrantObjectType objtype; + InternalGrant istmt; Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); /* We only operate on objects on the current database */ @@ -1113,11 +1119,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior) switch (sdepForm->deptype) { - ObjectAddress obj; - GrantObjectType objtype; - InternalGrant istmt; - - /* Shouldn't happen */ + /* Shouldn't happen */ case SHARED_DEPENDENCY_PIN: case SHARED_DEPENDENCY_INVALID: elog(ERROR, "unexpected dependency type"); @@ -1126,25 +1128,25 @@ shdepDropOwned(List *roleids, DropBehavior behavior) switch (sdepForm->classid) { case RelationRelationId: - { - /* is it a sequence or non-sequence? */ - Form_pg_class pg_class_tuple; - HeapTuple tuple; + { + /* is it a sequence or non-sequence? */ + Form_pg_class pg_class_tuple; + HeapTuple tuple; - tuple = SearchSysCache(RELOID, - ObjectIdGetDatum(sdepForm->objid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for relation %u", - sdepForm->objid); - pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); - if (pg_class_tuple->relkind == RELKIND_SEQUENCE) - istmt.objtype = ACL_OBJECT_SEQUENCE; - else - istmt.objtype = ACL_OBJECT_RELATION; - ReleaseSysCache(tuple); + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(sdepForm->objid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", + sdepForm->objid); + pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + istmt.objtype = ACL_OBJECT_SEQUENCE; + else + istmt.objtype = ACL_OBJECT_RELATION; + ReleaseSysCache(tuple); + } break; - } case DatabaseRelationId: istmt.objtype = ACL_OBJECT_DATABASE; break; @@ -1178,20 +1180,12 @@ shdepDropOwned(List *roleids, DropBehavior behavior) ExecGrantStmt_oids(&istmt); break; case SHARED_DEPENDENCY_OWNER: - - /* - * If there's a regular (non-shared) dependency on this - * object marked with DEPENDENCY_INTERNAL, skip this - * object. We will drop the referencer object instead. - */ - if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid)) - continue; - - /* Drop the object */ + /* Save it for later deleting it */ obj.classId = sdepForm->classid; obj.objectId = sdepForm->objid; obj.objectSubId = 0; - performDeletion(&obj, behavior); + + add_exact_object_address(&obj, deleteobjs); break; } } @@ -1199,7 +1193,12 @@ shdepDropOwned(List *roleids, DropBehavior behavior) systable_endscan(scan); } + /* the dependency mechanism does the actual work */ + performMultipleDeletions(deleteobjs, behavior); + heap_close(sdepRel, AccessExclusiveLock); + + free_object_addresses(deleteobjs); } /* diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index fbfe40e472..04dc3ac7f3 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.25 2006/06/27 18:35:05 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.26 2006/08/20 21:56:16 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -112,6 +112,8 @@ typedef struct ObjectAddress int32 objectSubId; /* Subitem within the object (column of table) */ } ObjectAddress; +/* expansible list of ObjectAddresses */ +typedef struct ObjectAddresses ObjectAddresses; /* * This enum covers all system catalogs whose OIDs can appear in @@ -144,6 +146,9 @@ typedef enum ObjectClass extern void performDeletion(const ObjectAddress *object, DropBehavior behavior); +extern void performMultipleDeletions(const ObjectAddresses *objects, + DropBehavior behavior); + extern void deleteWhatDependsOn(const ObjectAddress *object, bool showNotices); @@ -160,6 +165,16 @@ extern ObjectClass getObjectClass(const ObjectAddress *object); extern char *getObjectDescription(const ObjectAddress *object); +extern ObjectAddresses *new_object_addresses(void); + +extern void add_exact_object_address(const ObjectAddress *object, + ObjectAddresses *addrs); + +extern bool object_address_present(const ObjectAddress *object, + ObjectAddresses *addrs); + +extern void free_object_addresses(ObjectAddresses *addrs); + /* in pg_depend.c */ extern void recordDependencyOn(const ObjectAddress *depender,