Tom Lane wrote:
> Alvaro Herrera <[EMAIL PROTECTED]> writes:
> > Ok, this patch implements more or less this idea; except that instead of
> > checking the list of implicit dependencies for later objects, we iterate
> > twice on the list of objects to delete, and create a list of implicit
> > dependencies on all of them the first time, and delete those not on that
> > list the second time.
> 
> In the light of morning it occurs to me that probably the best code
> factoring for this is for dependency.c to export a
> performMultipleDeletions() function that takes an objectAddresses list
> of targets and does all the dependency-chasing internally.  This would
> reduce the amount of cruft that has to be exported from dependency.c.

Sounds a pretty obvious move.  This would be it then.  Please note the
changes to the ObjectAddresses stuff, mainly to not move the definition
of struct ObjectAddresses to dependency.h but instead move only the
typedef.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Index: src/backend/catalog/dependency.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/dependency.c,v
retrieving revision 1.58
diff -c -p -r1.58 dependency.c
*** src/backend/catalog/dependency.c    14 Jul 2006 14:52:17 -0000      1.58
--- src/backend/catalog/dependency.c    20 Aug 2006 17:29:03 -0000
***************
*** 57,68 ****
  
  
  /* expansible list of ObjectAddresses */
! typedef struct
  {
        ObjectAddress *refs;            /* => palloc'd array */
        int                     numrefs;                /* current number of 
references */
        int                     maxrefs;                /* current size of 
palloc'd array */
! } ObjectAddresses;
  
  /* for find_expr_references_walker */
  typedef struct
--- 57,70 ----
  
  
  /* expansible list of ObjectAddresses */
! struct ObjectAddresses
  {
        ObjectAddress *refs;            /* => palloc'd array */
        int                     numrefs;                /* current number of 
references */
        int                     maxrefs;                /* current size of 
palloc'd array */
!       bool            alloc;                  /* ObjectAddresses itself is 
palloc'ed? */
! };
! /* typedef ObjectAddresses appears in dependency.h */
  
  /* for find_expr_references_walker */
  typedef struct
*************** static const Oid object_classes[MAX_OCLA
*** 92,106 ****
  };
  
  
  static void findAutoDeletableObjects(const ObjectAddress *object,
                                                 ObjectAddresses *oktodelete,
!                                                Relation depRel);
  static bool recursiveDeletion(const ObjectAddress *object,
                                  DropBehavior behavior,
                                  int msglevel,
                                  const ObjectAddress *callingObject,
                                  ObjectAddresses *oktodelete,
!                                 Relation depRel);
  static bool deleteDependentObjects(const ObjectAddress *object,
                                           const char *objDescription,
                                           DropBehavior behavior,
--- 94,113 ----
  };
  
  
+ static void performDeletionWithList(const ObjectAddress *object,
+                                               ObjectAddresses *oktodelete,
+                                               DropBehavior behavior,
+                                               ObjectAddresses 
*alreadyDeleted);
  static void findAutoDeletableObjects(const ObjectAddress *object,
                                                 ObjectAddresses *oktodelete,
!                                                Relation depRel, bool addself);
  static bool recursiveDeletion(const ObjectAddress *object,
                                  DropBehavior behavior,
                                  int msglevel,
                                  const ObjectAddress *callingObject,
                                  ObjectAddresses *oktodelete,
!                                 Relation depRel,
!                                 ObjectAddresses *alreadyDeleted);
  static bool deleteDependentObjects(const ObjectAddress *object,
                                           const char *objDescription,
                                           DropBehavior behavior,
*************** static int      object_address_comparator(con
*** 115,125 ****
  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);
  
  
--- 122,127 ----
*************** performDeletion(const ObjectAddress *obj
*** 161,170 ****
         */
        init_object_addresses(&oktodelete);
  
!       findAutoDeletableObjects(object, &oktodelete, depRel);
  
        if (!recursiveDeletion(object, behavior, NOTICE,
!                                                  NULL, &oktodelete, depRel))
                ereport(ERROR,
                                (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
                                 errmsg("cannot drop %s because other objects 
depend on it",
--- 163,172 ----
         */
        init_object_addresses(&oktodelete);
  
!       findAutoDeletableObjects(object, &oktodelete, depRel, true);
  
        if (!recursiveDeletion(object, behavior, NOTICE,
!                                                  NULL, &oktodelete, depRel, 
NULL))
                ereport(ERROR,
                                (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
                                 errmsg("cannot drop %s because other objects 
depend on it",
*************** performDeletion(const ObjectAddress *obj
*** 180,185 ****
--- 182,313 ----
  
  
  /*
+  * 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 all lists for all objects.
+  */
+ void
+ performMultipleDeletions(const ObjectAddresses *objects,
+                                                DropBehavior behavior)
+ {
+       ObjectAddresses implicit;
+       ObjectAddresses alreadyDeleted;
+       Relation                depRel;
+       int                             i;
+ 
+       init_object_addresses(&implicit);
+       init_object_addresses(&alreadyDeleted);
+ 
+       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);
+ 
+       term_object_addresses(&implicit);
+       term_object_addresses(&alreadyDeleted);
+ }
+ 
+ /*
   * deleteWhatDependsOn: attempt to drop everything that depends on the
   * specified object, though not the object itself.    Behavior is always
   * CASCADE.
*************** deleteWhatDependsOn(const ObjectAddress 
*** 215,221 ****
         */
        init_object_addresses(&oktodelete);
  
!       findAutoDeletableObjects(object, &oktodelete, depRel);
  
        /*
         * Now invoke only step 2 of recursiveDeletion: just recurse to the 
stuff
--- 343,349 ----
         */
        init_object_addresses(&oktodelete);
  
!       findAutoDeletableObjects(object, &oktodelete, depRel, true);
  
        /*
         * Now invoke only step 2 of recursiveDeletion: just recurse to the 
stuff
*************** deleteWhatDependsOn(const ObjectAddress 
*** 246,260 ****
  /*
   * 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.
   *
   * depRel is the already-open pg_depend relation.
   */
  static void
  findAutoDeletableObjects(const ObjectAddress *object,
                                                 ObjectAddresses *oktodelete,
!                                                Relation depRel)
  {
        ScanKeyData key[3];
        int                     nkeys;
--- 374,388 ----
  /*
   * findAutoDeletableObjects: find all objects that are reachable by AUTO or
   * INTERNAL dependency paths from the given object.  Add them all to the
!  * 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, bool addself)
  {
        ScanKeyData key[3];
        int                     nkeys;
*************** findAutoDeletableObjects(const ObjectAdd
*** 269,275 ****
         */
        if (object_address_present(object, oktodelete))
                return;
!       add_exact_object_address(object, oktodelete);
  
        /*
         * Scan pg_depend records that link to this object, showing the things
--- 397,404 ----
         */
        if (object_address_present(object, oktodelete))
                return;
!       if (addself)
!               add_exact_object_address(object, oktodelete);
  
        /*
         * Scan pg_depend records that link to this object, showing the things
*************** findAutoDeletableObjects(const ObjectAdd
*** 316,322 ****
                                otherObject.classId = foundDep->classid;
                                otherObject.objectId = foundDep->objid;
                                otherObject.objectSubId = foundDep->objsubid;
!                               findAutoDeletableObjects(&otherObject, 
oktodelete, depRel);
                                break;
                        case DEPENDENCY_PIN:
  
--- 445,451 ----
                                otherObject.classId = foundDep->classid;
                                otherObject.objectId = foundDep->objid;
                                otherObject.objectSubId = foundDep->objsubid;
!                               findAutoDeletableObjects(&otherObject, 
oktodelete, depRel, true);
                                break;
                        case DEPENDENCY_PIN:
  
*************** recursiveDeletion(const ObjectAddress *o
*** 387,393 ****
                                  int msglevel,
                                  const ObjectAddress *callingObject,
                                  ObjectAddresses *oktodelete,
!                                 Relation depRel)
  {
        bool            ok = true;
        char       *objDescription;
--- 516,523 ----
                                  int msglevel,
                                  const ObjectAddress *callingObject,
                                  ObjectAddresses *oktodelete,
!                                 Relation depRel,
!                                 ObjectAddresses *alreadyDeleted)
  {
        bool            ok = true;
        char       *objDescription;
*************** recursiveDeletion(const ObjectAddress *o
*** 553,559 ****
                                                        
getObjectDescription(&owningObject))));
  
                if (!recursiveDeletion(&owningObject, behavior, msglevel,
!                                                          object, oktodelete, 
depRel))
                        ok = false;
  
                pfree(objDescription);
--- 683,689 ----
                                                        
getObjectDescription(&owningObject))));
  
                if (!recursiveDeletion(&owningObject, behavior, msglevel,
!                                                          object, oktodelete, 
depRel, alreadyDeleted))
                        ok = false;
  
                pfree(objDescription);
*************** recursiveDeletion(const ObjectAddress *o
*** 579,587 ****
         */
  
        /*
!        * Step 3: delete the object itself.
         */
        doDeletion(object);
  
        /*
         * Delete any comments associated with this object.  (This is a 
convenient
--- 709,723 ----
         */
  
        /*
!        * 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
*************** deleteDependentObjects(const ObjectAddre
*** 712,718 ****
                                                                        
getObjectDescription(&otherObject))));
  
                                if (!recursiveDeletion(&otherObject, behavior, 
msglevel,
!                                                                          
object, oktodelete, depRel))
                                        ok = false;
                                break;
                        case DEPENDENCY_AUTO:
--- 848,854 ----
                                                                        
getObjectDescription(&otherObject))));
  
                                if (!recursiveDeletion(&otherObject, behavior, 
msglevel,
!                                                                          
object, oktodelete, depRel, NULL))
                                        ok = false;
                                break;
                        case DEPENDENCY_AUTO:
*************** deleteDependentObjects(const ObjectAddre
*** 728,734 ****
                                                                
getObjectDescription(&otherObject))));
  
                                if (!recursiveDeletion(&otherObject, behavior, 
msglevel,
!                                                                          
object, oktodelete, depRel))
                                        ok = false;
                                break;
                        case DEPENDENCY_PIN:
--- 864,870 ----
                                                                
getObjectDescription(&otherObject))));
  
                                if (!recursiveDeletion(&otherObject, behavior, 
msglevel,
!                                                                          
object, oktodelete, depRel, NULL))
                                        ok = false;
                                break;
                        case DEPENDENCY_PIN:
*************** object_address_comparator(const void *a,
*** 1332,1337 ****
--- 1468,1492 ----
  /*
   * Routines for handling an expansible array of ObjectAddress items.
   *
+  * new_object_addresses: create a new ObjectAddresses array.
+  */
+ ObjectAddresses *
+ new_object_addresses(void)
+ {
+       ObjectAddresses   *addrs;
+ 
+       addrs = palloc(sizeof(ObjectAddresses));
+ 
+       addrs->numrefs = 0;
+       addrs->maxrefs = 32;
+       addrs->refs = (ObjectAddress *)
+               palloc(addrs->maxrefs * sizeof(ObjectAddress));
+       addrs->alloc = true;
+ 
+       return addrs;
+ }
+ 
+ /*
   * init_object_addresses: initialize an ObjectAddresses array.
   */
  static void
*************** init_object_addresses(ObjectAddresses *a
*** 1342,1347 ****
--- 1497,1503 ----
        addrs->maxrefs = 32;            /* arbitrary initial array size */
        addrs->refs = (ObjectAddress *)
                palloc(addrs->maxrefs * sizeof(ObjectAddress));
+       addrs->alloc = false;
  }
  
  /*
*************** add_object_address(ObjectClass oclass, O
*** 1376,1382 ****
   *
   * As above, but specify entry exactly.
   */
! static void
  add_exact_object_address(const ObjectAddress *object,
                                                 ObjectAddresses *addrs)
  {
--- 1532,1538 ----
   *
   * As above, but specify entry exactly.
   */
! void
  add_exact_object_address(const ObjectAddress *object,
                                                 ObjectAddresses *addrs)
  {
*************** add_exact_object_address(const ObjectAdd
*** 1400,1406 ****
   *
   * We return "true" if object is a subobject of something in the array, too.
   */
! static bool
  object_address_present(const ObjectAddress *object,
                                           ObjectAddresses *addrs)
  {
--- 1556,1562 ----
   *
   * We return "true" if object is a subobject of something in the array, too.
   */
! bool
  object_address_present(const ObjectAddress *object,
                                           ObjectAddresses *addrs)
  {
*************** object_address_present(const ObjectAddre
*** 1425,1434 ****
  /*
   * Clean up when done with an ObjectAddresses array.
   */
! static void
  term_object_addresses(ObjectAddresses *addrs)
  {
        pfree(addrs->refs);
  }
  
  /*
--- 1581,1592 ----
  /*
   * Clean up when done with an ObjectAddresses array.
   */
! void
  term_object_addresses(ObjectAddresses *addrs)
  {
        pfree(addrs->refs);
+       if (addrs->alloc)
+               pfree(addrs);
  }
  
  /*
Index: src/backend/catalog/pg_shdepend.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_shdepend.c,v
retrieving revision 1.12
diff -c -p -r1.12 pg_shdepend.c
*** src/backend/catalog/pg_shdepend.c   14 Jul 2006 14:52:18 -0000      1.12
--- src/backend/catalog/pg_shdepend.c   20 Aug 2006 17:26:58 -0000
*************** shdepDropOwned(List *roleids, DropBehavi
*** 1061,1066 ****
--- 1061,1069 ----
  {
        Relation        sdepRel;
        ListCell   *cell;
+       ObjectAddresses *deleteobjs;
+ 
+       deleteobjs = new_object_addresses();
  
        sdepRel = heap_open(SharedDependRelationId, AccessExclusiveLock);
  
*************** shdepDropOwned(List *roleids, DropBehavi
*** 1105,1110 ****
--- 1108,1116 ----
  
                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 */
*************** shdepDropOwned(List *roleids, DropBehavi
*** 1113,1123 ****
  
                        switch (sdepForm->deptype)
                        {
!                                       ObjectAddress obj;
!                                       GrantObjectType objtype;
!                                       InternalGrant istmt;
! 
!                                       /* Shouldn't happen */
                                case SHARED_DEPENDENCY_PIN:
                                case SHARED_DEPENDENCY_INVALID:
                                        elog(ERROR, "unexpected dependency 
type");
--- 1119,1125 ----
  
                        switch (sdepForm->deptype)
                        {
!                               /* Shouldn't happen */
                                case SHARED_DEPENDENCY_PIN:
                                case SHARED_DEPENDENCY_INVALID:
                                        elog(ERROR, "unexpected dependency 
type");
*************** shdepDropOwned(List *roleids, DropBehavi
*** 1126,1150 ****
                                        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);
                                                        break;
-                                               }
                                                case DatabaseRelationId:
                                                        istmt.objtype = 
ACL_OBJECT_DATABASE;
                                                        break;
--- 1128,1152 ----
                                        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);
!                                                       }
                                                        break;
                                                case DatabaseRelationId:
                                                        istmt.objtype = 
ACL_OBJECT_DATABASE;
                                                        break;
*************** shdepDropOwned(List *roleids, DropBehavi
*** 1178,1197 ****
                                        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 */
                                        obj.classId = sdepForm->classid;
                                        obj.objectId = sdepForm->objid;
                                        obj.objectSubId = 0;
!                                       performDeletion(&obj, behavior);
                                        break;
                        }
                }
--- 1180,1191 ----
                                        ExecGrantStmt_oids(&istmt);
                                        break;
                                case SHARED_DEPENDENCY_OWNER:
!                                       /* Save it for later deleting it */
                                        obj.classId = sdepForm->classid;
                                        obj.objectId = sdepForm->objid;
                                        obj.objectSubId = 0;
! 
!                                       add_exact_object_address(&obj, 
deleteobjs);
                                        break;
                        }
                }
*************** shdepDropOwned(List *roleids, DropBehavi
*** 1199,1205 ****
--- 1193,1204 ----
                systable_endscan(scan);
        }
  
+       /* the dependency mechanism does the actual work */
+       performMultipleDeletions(deleteobjs, behavior);
+ 
        heap_close(sdepRel, AccessExclusiveLock);
+ 
+       term_object_addresses(deleteobjs);
  }
  
  /*
Index: src/include/catalog/dependency.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/dependency.h,v
retrieving revision 1.25
diff -c -p -r1.25 dependency.h
*** src/include/catalog/dependency.h    27 Jun 2006 18:35:05 -0000      1.25
--- src/include/catalog/dependency.h    20 Aug 2006 17:30:05 -0000
*************** typedef struct ObjectAddress
*** 112,117 ****
--- 112,119 ----
        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
*************** typedef enum ObjectClass
*** 144,149 ****
--- 146,154 ----
  extern void performDeletion(const ObjectAddress *object,
                                DropBehavior behavior);
  
+ extern void performMultipleDeletions(const ObjectAddresses *objects,
+                                                DropBehavior behavior);
+ 
  extern void deleteWhatDependsOn(const ObjectAddress *object,
                                        bool showNotices);
  
*************** extern ObjectClass getObjectClass(const 
*** 160,165 ****
--- 165,180 ----
  
  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 term_object_addresses(ObjectAddresses *addrs);
+ 
  /* in pg_depend.c */
  
  extern void recordDependencyOn(const ObjectAddress *depender,
---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

Reply via email to