aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/dependency.c300
-rw-r--r--src/backend/catalog/pg_shdepend.c69
-rw-r--r--src/include/catalog/dependency.h17
3 files changed, 270 insertions, 116 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 13a1a35c659..7007e838734 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);
@@ -180,6 +180,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
* CASCADE.
@@ -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 a0580a6bd85..31f1f654de0 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;
-
- 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);
+ {
+ /* 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);
+ }
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 fbfe40e472f..04dc3ac7f3a 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,