Fix DROP OWNED BY to correctly consider the implicitly-deleted objects list for

each object to be deleted, instead of the previous hack that just skipped
INTERNAL dependencies, which didn't really work.  Per report from Tom Lane.

To do this, introduce a new performMultipleDeletions entry point in
dependency.c to delete multiple objects at once.  The dependency code then has
the responsability of tracking INTERNAL and AUTO dependencies as needed.

Along the way, change ObjectAddresses so that we can allocate an ObjectAddress
list from outside dependency.c and not have to export the internal
representation.
This commit is contained in:
Alvaro Herrera 2006-08-20 21:56:16 +00:00
parent 4e23d6e07d
commit df18c51f29
3 changed files with 269 additions and 115 deletions

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 */ /* expansible list of ObjectAddresses */
typedef struct struct ObjectAddresses
{ {
ObjectAddress *refs; /* => palloc'd array */ ObjectAddress *refs; /* => palloc'd array */
int numrefs; /* current number of references */ int numrefs; /* current number of references */
int maxrefs; /* current size of palloc'd array */ int maxrefs; /* current size of palloc'd array */
} ObjectAddresses; };
/* typedef ObjectAddresses appears in dependency.h */
/* for find_expr_references_walker */ /* for find_expr_references_walker */
typedef struct typedef struct
{ {
ObjectAddresses addrs; /* addresses being accumulated */ ObjectAddresses *addrs; /* addresses being accumulated */
List *rtables; /* list of rangetables to resolve Vars */ List *rtables; /* list of rangetables to resolve Vars */
} find_expr_references_context; } 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, static void findAutoDeletableObjects(const ObjectAddress *object,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel); Relation depRel, bool addself);
static bool recursiveDeletion(const ObjectAddress *object, static bool recursiveDeletion(const ObjectAddress *object,
DropBehavior behavior, DropBehavior behavior,
int msglevel, int msglevel,
const ObjectAddress *callingObject, const ObjectAddress *callingObject,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel); Relation depRel,
ObjectAddresses *alreadyDeleted);
static bool deleteDependentObjects(const ObjectAddress *object, static bool deleteDependentObjects(const ObjectAddress *object,
const char *objDescription, const char *objDescription,
DropBehavior behavior, DropBehavior behavior,
@ -112,14 +118,8 @@ static bool find_expr_references_walker(Node *node,
find_expr_references_context *context); find_expr_references_context *context);
static void eliminate_duplicate_dependencies(ObjectAddresses *addrs); static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
static int object_address_comparator(const void *a, const void *b); 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, static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
ObjectAddresses *addrs); 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); static void getRelationDescription(StringInfo buffer, Oid relid);
@ -139,7 +139,7 @@ performDeletion(const ObjectAddress *object,
{ {
char *objDescription; char *objDescription;
Relation depRel; Relation depRel;
ObjectAddresses oktodelete; ObjectAddresses *oktodelete;
/* /*
* Get object description for possible use in failure message. Must do * 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 * even if the actual deletion pass first reaches one of them via a
* non-auto dependency. * 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, if (!recursiveDeletion(object, behavior, NOTICE,
NULL, &oktodelete, depRel)) NULL, oktodelete, depRel, NULL))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because other objects depend on it", errmsg("cannot drop %s because other objects depend on it",
objDescription), objDescription),
errhint("Use DROP ... CASCADE to drop the dependent objects too."))); errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
term_object_addresses(&oktodelete); free_object_addresses(oktodelete);
heap_close(depRel, RowExclusiveLock); 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 * deleteWhatDependsOn: attempt to drop everything that depends on the
* specified object, though not the object itself. Behavior is always * specified object, though not the object itself. Behavior is always
@ -194,7 +320,7 @@ deleteWhatDependsOn(const ObjectAddress *object,
{ {
char *objDescription; char *objDescription;
Relation depRel; Relation depRel;
ObjectAddresses oktodelete; ObjectAddresses *oktodelete;
/* /*
* Get object description for possible use in failure messages * 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 * even if the actual deletion pass first reaches one of them via a
* non-auto dependency. * 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 * Now invoke only step 2 of recursiveDeletion: just recurse to the stuff
@ -224,7 +350,7 @@ deleteWhatDependsOn(const ObjectAddress *object,
if (!deleteDependentObjects(object, objDescription, if (!deleteDependentObjects(object, objDescription,
DROP_CASCADE, DROP_CASCADE,
showNotices ? NOTICE : DEBUG2, showNotices ? NOTICE : DEBUG2,
&oktodelete, depRel)) oktodelete, depRel))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("failed to drop all objects depending on %s", 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. * anything then each recursive call will have ended with one.
*/ */
term_object_addresses(&oktodelete); free_object_addresses(oktodelete);
heap_close(depRel, RowExclusiveLock); heap_close(depRel, RowExclusiveLock);
@ -246,15 +372,15 @@ deleteWhatDependsOn(const ObjectAddress *object,
/* /*
* findAutoDeletableObjects: find all objects that are reachable by AUTO or * findAutoDeletableObjects: find all objects that are reachable by AUTO or
* INTERNAL dependency paths from the given object. Add them all to the * INTERNAL dependency paths from the given object. Add them all to the
* oktodelete list. Note that the originally given object will also be * oktodelete list. If addself is true, the originally given object will also
* added to the list. * be added to the list.
* *
* depRel is the already-open pg_depend relation. * depRel is the already-open pg_depend relation.
*/ */
static void static void
findAutoDeletableObjects(const ObjectAddress *object, findAutoDeletableObjects(const ObjectAddress *object,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel) Relation depRel, bool addself)
{ {
ScanKeyData key[3]; ScanKeyData key[3];
int nkeys; int nkeys;
@ -269,7 +395,8 @@ findAutoDeletableObjects(const ObjectAddress *object,
*/ */
if (object_address_present(object, oktodelete)) if (object_address_present(object, oktodelete))
return; 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 * 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.classId = foundDep->classid;
otherObject.objectId = foundDep->objid; otherObject.objectId = foundDep->objid;
otherObject.objectSubId = foundDep->objsubid; otherObject.objectSubId = foundDep->objsubid;
findAutoDeletableObjects(&otherObject, oktodelete, depRel); findAutoDeletableObjects(&otherObject, oktodelete, depRel, true);
break; break;
case DEPENDENCY_PIN: case DEPENDENCY_PIN:
@ -387,7 +514,8 @@ recursiveDeletion(const ObjectAddress *object,
int msglevel, int msglevel,
const ObjectAddress *callingObject, const ObjectAddress *callingObject,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel) Relation depRel,
ObjectAddresses *alreadyDeleted)
{ {
bool ok = true; bool ok = true;
char *objDescription; char *objDescription;
@ -553,7 +681,7 @@ recursiveDeletion(const ObjectAddress *object,
getObjectDescription(&owningObject)))); getObjectDescription(&owningObject))));
if (!recursiveDeletion(&owningObject, behavior, msglevel, if (!recursiveDeletion(&owningObject, behavior, msglevel,
object, oktodelete, depRel)) object, oktodelete, depRel, alreadyDeleted))
ok = false; ok = false;
pfree(objDescription); 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); 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 * Delete any comments associated with this object. (This is a convenient
@ -712,7 +846,7 @@ deleteDependentObjects(const ObjectAddress *object,
getObjectDescription(&otherObject)))); getObjectDescription(&otherObject))));
if (!recursiveDeletion(&otherObject, behavior, msglevel, if (!recursiveDeletion(&otherObject, behavior, msglevel,
object, oktodelete, depRel)) object, oktodelete, depRel, NULL))
ok = false; ok = false;
break; break;
case DEPENDENCY_AUTO: case DEPENDENCY_AUTO:
@ -728,7 +862,7 @@ deleteDependentObjects(const ObjectAddress *object,
getObjectDescription(&otherObject)))); getObjectDescription(&otherObject))));
if (!recursiveDeletion(&otherObject, behavior, msglevel, if (!recursiveDeletion(&otherObject, behavior, msglevel,
object, oktodelete, depRel)) object, oktodelete, depRel, NULL))
ok = false; ok = false;
break; break;
case DEPENDENCY_PIN: case DEPENDENCY_PIN:
@ -858,7 +992,7 @@ recordDependencyOnExpr(const ObjectAddress *depender,
{ {
find_expr_references_context context; find_expr_references_context context;
init_object_addresses(&context.addrs); context.addrs = new_object_addresses();
/* Set up interpretation for Vars at varlevelsup = 0 */ /* Set up interpretation for Vars at varlevelsup = 0 */
context.rtables = list_make1(rtable); context.rtables = list_make1(rtable);
@ -867,14 +1001,14 @@ recordDependencyOnExpr(const ObjectAddress *depender,
find_expr_references_walker(expr, &context); find_expr_references_walker(expr, &context);
/* Remove any duplicates */ /* Remove any duplicates */
eliminate_duplicate_dependencies(&context.addrs); eliminate_duplicate_dependencies(context.addrs);
/* And record 'em */ /* And record 'em */
recordMultipleDependencies(depender, recordMultipleDependencies(depender,
context.addrs.refs, context.addrs.numrefs, context.addrs->refs, context.addrs->numrefs,
behavior); behavior);
term_object_addresses(&context.addrs); free_object_addresses(context.addrs);
} }
/* /*
@ -895,7 +1029,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
find_expr_references_context context; find_expr_references_context context;
RangeTblEntry rte; RangeTblEntry rte;
init_object_addresses(&context.addrs); context.addrs = new_object_addresses();
/* We gin up a rather bogus rangetable list to handle Vars */ /* We gin up a rather bogus rangetable list to handle Vars */
MemSet(&rte, 0, sizeof(rte)); MemSet(&rte, 0, sizeof(rte));
@ -909,30 +1043,30 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
find_expr_references_walker(expr, &context); find_expr_references_walker(expr, &context);
/* Remove any duplicates */ /* Remove any duplicates */
eliminate_duplicate_dependencies(&context.addrs); eliminate_duplicate_dependencies(context.addrs);
/* Separate self-dependencies if necessary */ /* 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; ObjectAddress *outobj;
int oldref, int oldref,
outrefs; outrefs;
init_object_addresses(&self_addrs); self_addrs = new_object_addresses();
outobj = context.addrs.refs; outobj = context.addrs->refs;
outrefs = 0; 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 && if (thisobj->classId == RelationRelationId &&
thisobj->objectId == relId) thisobj->objectId == relId)
{ {
/* Move this ref into self_addrs */ /* Move this ref into self_addrs */
add_object_address(OCLASS_CLASS, relId, thisobj->objectSubId, add_object_address(OCLASS_CLASS, relId, thisobj->objectSubId,
&self_addrs); self_addrs);
} }
else else
{ {
@ -944,22 +1078,22 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
outrefs++; outrefs++;
} }
} }
context.addrs.numrefs = outrefs; context.addrs->numrefs = outrefs;
/* Record the self-dependencies */ /* Record the self-dependencies */
recordMultipleDependencies(depender, recordMultipleDependencies(depender,
self_addrs.refs, self_addrs.numrefs, self_addrs->refs, self_addrs->numrefs,
self_behavior); self_behavior);
term_object_addresses(&self_addrs); free_object_addresses(self_addrs);
} }
/* Record the external dependencies */ /* Record the external dependencies */
recordMultipleDependencies(depender, recordMultipleDependencies(depender,
context.addrs.refs, context.addrs.numrefs, context.addrs->refs, context.addrs->numrefs,
behavior); 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 */ /* If it's a plain relation, reference this column */
add_object_address(OCLASS_CLASS, rte->relid, var->varattno, add_object_address(OCLASS_CLASS, rte->relid, var->varattno,
&context->addrs); context->addrs);
} }
else if (rte->rtekind == RTE_JOIN) 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 */ /* A constant must depend on the constant's datatype */
add_object_address(OCLASS_TYPE, con->consttype, 0, add_object_address(OCLASS_TYPE, con->consttype, 0,
&context->addrs); context->addrs);
/* /*
* If it's a regclass or similar literal referring to an existing * If it's a regclass or similar literal referring to an existing
@ -1056,7 +1190,7 @@ find_expr_references_walker(Node *node,
ObjectIdGetDatum(objoid), ObjectIdGetDatum(objoid),
0, 0, 0)) 0, 0, 0))
add_object_address(OCLASS_PROC, objoid, 0, add_object_address(OCLASS_PROC, objoid, 0,
&context->addrs); context->addrs);
break; break;
case REGOPEROID: case REGOPEROID:
case REGOPERATOROID: case REGOPERATOROID:
@ -1065,7 +1199,7 @@ find_expr_references_walker(Node *node,
ObjectIdGetDatum(objoid), ObjectIdGetDatum(objoid),
0, 0, 0)) 0, 0, 0))
add_object_address(OCLASS_OPERATOR, objoid, 0, add_object_address(OCLASS_OPERATOR, objoid, 0,
&context->addrs); context->addrs);
break; break;
case REGCLASSOID: case REGCLASSOID:
objoid = DatumGetObjectId(con->constvalue); objoid = DatumGetObjectId(con->constvalue);
@ -1073,7 +1207,7 @@ find_expr_references_walker(Node *node,
ObjectIdGetDatum(objoid), ObjectIdGetDatum(objoid),
0, 0, 0)) 0, 0, 0))
add_object_address(OCLASS_CLASS, objoid, 0, add_object_address(OCLASS_CLASS, objoid, 0,
&context->addrs); context->addrs);
break; break;
case REGTYPEOID: case REGTYPEOID:
objoid = DatumGetObjectId(con->constvalue); objoid = DatumGetObjectId(con->constvalue);
@ -1081,7 +1215,7 @@ find_expr_references_walker(Node *node,
ObjectIdGetDatum(objoid), ObjectIdGetDatum(objoid),
0, 0, 0)) 0, 0, 0))
add_object_address(OCLASS_TYPE, objoid, 0, add_object_address(OCLASS_TYPE, objoid, 0,
&context->addrs); context->addrs);
break; break;
} }
} }
@ -1093,14 +1227,14 @@ find_expr_references_walker(Node *node,
/* A parameter must depend on the parameter's datatype */ /* A parameter must depend on the parameter's datatype */
add_object_address(OCLASS_TYPE, param->paramtype, 0, add_object_address(OCLASS_TYPE, param->paramtype, 0,
&context->addrs); context->addrs);
} }
if (IsA(node, FuncExpr)) if (IsA(node, FuncExpr))
{ {
FuncExpr *funcexpr = (FuncExpr *) node; FuncExpr *funcexpr = (FuncExpr *) node;
add_object_address(OCLASS_PROC, funcexpr->funcid, 0, add_object_address(OCLASS_PROC, funcexpr->funcid, 0,
&context->addrs); context->addrs);
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
if (IsA(node, OpExpr)) if (IsA(node, OpExpr))
@ -1108,7 +1242,7 @@ find_expr_references_walker(Node *node,
OpExpr *opexpr = (OpExpr *) node; OpExpr *opexpr = (OpExpr *) node;
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
&context->addrs); context->addrs);
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
if (IsA(node, DistinctExpr)) if (IsA(node, DistinctExpr))
@ -1116,7 +1250,7 @@ find_expr_references_walker(Node *node,
DistinctExpr *distinctexpr = (DistinctExpr *) node; DistinctExpr *distinctexpr = (DistinctExpr *) node;
add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0, add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
&context->addrs); context->addrs);
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
if (IsA(node, ScalarArrayOpExpr)) if (IsA(node, ScalarArrayOpExpr))
@ -1124,7 +1258,7 @@ find_expr_references_walker(Node *node,
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
&context->addrs); context->addrs);
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
if (IsA(node, NullIfExpr)) if (IsA(node, NullIfExpr))
@ -1132,7 +1266,7 @@ find_expr_references_walker(Node *node,
NullIfExpr *nullifexpr = (NullIfExpr *) node; NullIfExpr *nullifexpr = (NullIfExpr *) node;
add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0, add_object_address(OCLASS_OPERATOR, nullifexpr->opno, 0,
&context->addrs); context->addrs);
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
if (IsA(node, Aggref)) if (IsA(node, Aggref))
@ -1140,7 +1274,7 @@ find_expr_references_walker(Node *node,
Aggref *aggref = (Aggref *) node; Aggref *aggref = (Aggref *) node;
add_object_address(OCLASS_PROC, aggref->aggfnoid, 0, add_object_address(OCLASS_PROC, aggref->aggfnoid, 0,
&context->addrs); context->addrs);
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
if (is_subplan(node)) 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 */ /* since there is no function dependency, need to depend on type */
add_object_address(OCLASS_TYPE, relab->resulttype, 0, add_object_address(OCLASS_TYPE, relab->resulttype, 0,
&context->addrs); context->addrs);
} }
if (IsA(node, ConvertRowtypeExpr)) 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 */ /* since there is no function dependency, need to depend on type */
add_object_address(OCLASS_TYPE, cvt->resulttype, 0, add_object_address(OCLASS_TYPE, cvt->resulttype, 0,
&context->addrs); context->addrs);
} }
if (IsA(node, RowExpr)) if (IsA(node, RowExpr))
{ {
RowExpr *rowexpr = (RowExpr *) node; RowExpr *rowexpr = (RowExpr *) node;
add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0, add_object_address(OCLASS_TYPE, rowexpr->row_typeid, 0,
&context->addrs); context->addrs);
} }
if (IsA(node, RowCompareExpr)) if (IsA(node, RowCompareExpr))
{ {
@ -1179,12 +1313,12 @@ find_expr_references_walker(Node *node,
foreach(l, rcexpr->opnos) foreach(l, rcexpr->opnos)
{ {
add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0, add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
&context->addrs); context->addrs);
} }
foreach(l, rcexpr->opclasses) foreach(l, rcexpr->opclasses)
{ {
add_object_address(OCLASS_OPCLASS, lfirst_oid(l), 0, add_object_address(OCLASS_OPCLASS, lfirst_oid(l), 0,
&context->addrs); context->addrs);
} }
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
@ -1193,7 +1327,7 @@ find_expr_references_walker(Node *node,
CoerceToDomain *cd = (CoerceToDomain *) node; CoerceToDomain *cd = (CoerceToDomain *) node;
add_object_address(OCLASS_TYPE, cd->resulttype, 0, add_object_address(OCLASS_TYPE, cd->resulttype, 0,
&context->addrs); context->addrs);
} }
if (IsA(node, Query)) if (IsA(node, Query))
{ {
@ -1218,13 +1352,13 @@ find_expr_references_walker(Node *node,
{ {
case RTE_RELATION: case RTE_RELATION:
add_object_address(OCLASS_CLASS, rte->relid, 0, add_object_address(OCLASS_CLASS, rte->relid, 0,
&context->addrs); context->addrs);
break; break;
case RTE_FUNCTION: case RTE_FUNCTION:
foreach(ct, rte->funccoltypes) foreach(ct, rte->funccoltypes)
{ {
add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0, add_object_address(OCLASS_TYPE, lfirst_oid(ct), 0,
&context->addrs); context->addrs);
} }
break; break;
default: default:
@ -1332,16 +1466,21 @@ object_address_comparator(const void *a, const void *b)
/* /*
* Routines for handling an expansible array of ObjectAddress items. * 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 ObjectAddresses *
init_object_addresses(ObjectAddresses *addrs) new_object_addresses(void)
{ {
/* Initialize array to empty */ ObjectAddresses *addrs;
addrs = palloc(sizeof(ObjectAddresses));
addrs->numrefs = 0; addrs->numrefs = 0;
addrs->maxrefs = 32; /* arbitrary initial array size */ addrs->maxrefs = 32;
addrs->refs = (ObjectAddress *) addrs->refs = (ObjectAddress *)
palloc(addrs->maxrefs * sizeof(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. * As above, but specify entry exactly.
*/ */
static void void
add_exact_object_address(const ObjectAddress *object, add_exact_object_address(const ObjectAddress *object,
ObjectAddresses *addrs) 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. * We return "true" if object is a subobject of something in the array, too.
*/ */
static bool bool
object_address_present(const ObjectAddress *object, object_address_present(const ObjectAddress *object,
ObjectAddresses *addrs) ObjectAddresses *addrs)
{ {
@ -1425,10 +1564,11 @@ object_address_present(const ObjectAddress *object,
/* /*
* Clean up when done with an ObjectAddresses array. * Clean up when done with an ObjectAddresses array.
*/ */
static void void
term_object_addresses(ObjectAddresses *addrs) free_object_addresses(ObjectAddresses *addrs)
{ {
pfree(addrs->refs); pfree(addrs->refs);
pfree(addrs);
} }
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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; Relation sdepRel;
ListCell *cell; ListCell *cell;
ObjectAddresses *deleteobjs;
deleteobjs = new_object_addresses();
sdepRel = heap_open(SharedDependRelationId, AccessExclusiveLock); sdepRel = heap_open(SharedDependRelationId, AccessExclusiveLock);
@ -1105,6 +1108,9 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
while ((tuple = systable_getnext(scan)) != NULL) while ((tuple = systable_getnext(scan)) != NULL)
{ {
ObjectAddress obj;
GrantObjectType objtype;
InternalGrant istmt;
Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple); Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
/* We only operate on objects on the current database */ /* We only operate on objects on the current database */
@ -1113,11 +1119,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
switch (sdepForm->deptype) switch (sdepForm->deptype)
{ {
ObjectAddress obj; /* Shouldn't happen */
GrantObjectType objtype;
InternalGrant istmt;
/* Shouldn't happen */
case SHARED_DEPENDENCY_PIN: case SHARED_DEPENDENCY_PIN:
case SHARED_DEPENDENCY_INVALID: case SHARED_DEPENDENCY_INVALID:
elog(ERROR, "unexpected dependency type"); elog(ERROR, "unexpected dependency type");
@ -1126,25 +1128,25 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
switch (sdepForm->classid) switch (sdepForm->classid)
{ {
case RelationRelationId: case RelationRelationId:
{ {
/* is it a sequence or non-sequence? */ /* is it a sequence or non-sequence? */
Form_pg_class pg_class_tuple; Form_pg_class pg_class_tuple;
HeapTuple tuple; HeapTuple tuple;
tuple = SearchSysCache(RELOID, tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(sdepForm->objid), ObjectIdGetDatum(sdepForm->objid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for relation %u", elog(ERROR, "cache lookup failed for relation %u",
sdepForm->objid); sdepForm->objid);
pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
if (pg_class_tuple->relkind == RELKIND_SEQUENCE) if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
istmt.objtype = ACL_OBJECT_SEQUENCE; istmt.objtype = ACL_OBJECT_SEQUENCE;
else else
istmt.objtype = ACL_OBJECT_RELATION; istmt.objtype = ACL_OBJECT_RELATION;
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
}
break; break;
}
case DatabaseRelationId: case DatabaseRelationId:
istmt.objtype = ACL_OBJECT_DATABASE; istmt.objtype = ACL_OBJECT_DATABASE;
break; break;
@ -1178,20 +1180,12 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
ExecGrantStmt_oids(&istmt); ExecGrantStmt_oids(&istmt);
break; break;
case SHARED_DEPENDENCY_OWNER: case SHARED_DEPENDENCY_OWNER:
/* Save it for later deleting it */
/*
* 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 */
obj.classId = sdepForm->classid; obj.classId = sdepForm->classid;
obj.objectId = sdepForm->objid; obj.objectId = sdepForm->objid;
obj.objectSubId = 0; obj.objectSubId = 0;
performDeletion(&obj, behavior);
add_exact_object_address(&obj, deleteobjs);
break; break;
} }
} }
@ -1199,7 +1193,12 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
systable_endscan(scan); systable_endscan(scan);
} }
/* the dependency mechanism does the actual work */
performMultipleDeletions(deleteobjs, behavior);
heap_close(sdepRel, AccessExclusiveLock); heap_close(sdepRel, AccessExclusiveLock);
free_object_addresses(deleteobjs);
} }
/* /*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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) */ int32 objectSubId; /* Subitem within the object (column of table) */
} ObjectAddress; } ObjectAddress;
/* expansible list of ObjectAddresses */
typedef struct ObjectAddresses ObjectAddresses;
/* /*
* This enum covers all system catalogs whose OIDs can appear in * This enum covers all system catalogs whose OIDs can appear in
@ -144,6 +146,9 @@ typedef enum ObjectClass
extern void performDeletion(const ObjectAddress *object, extern void performDeletion(const ObjectAddress *object,
DropBehavior behavior); DropBehavior behavior);
extern void performMultipleDeletions(const ObjectAddresses *objects,
DropBehavior behavior);
extern void deleteWhatDependsOn(const ObjectAddress *object, extern void deleteWhatDependsOn(const ObjectAddress *object,
bool showNotices); bool showNotices);
@ -160,6 +165,16 @@ extern ObjectClass getObjectClass(const ObjectAddress *object);
extern char *getObjectDescription(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 */ /* in pg_depend.c */
extern void recordDependencyOn(const ObjectAddress *depender, extern void recordDependencyOn(const ObjectAddress *depender,