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
*
* 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);
}
/*

View File

@ -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);
}
/*

View File

@ -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,