OSDN Git Service

8.4 pgindent run, with new combined Linux/FreeBSD/MinGW typedef list
[pg-rex/syncrep.git] / src / backend / catalog / pg_shdepend.c
index deac9a7..08977c3 100644 (file)
@@ -3,12 +3,12 @@
  * pg_shdepend.c
  *       routines to support manipulation of the pg_shdepend relation
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.9 2006/05/04 16:07:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.34 2009/06/11 14:48:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,8 @@
 
 #include "access/genam.h"
 #include "access/heapam.h"
-#include "utils/acl.h"
+#include "access/xact.h"
+#include "catalog/catalog.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_type.h"
 #include "commands/conversioncmds.h"
 #include "commands/defrem.h"
+#include "commands/proclang.h"
 #include "commands/schemacmds.h"
 #include "commands/tablecmds.h"
 #include "commands/typecmds.h"
-#include "lib/stringinfo.h"
+#include "storage/lmgr.h"
 #include "miscadmin.h"
+#include "utils/acl.h"
 #include "utils/fmgroids.h"
 #include "utils/syscache.h"
+#include "utils/tqual.h"
 
 
 typedef enum
@@ -51,13 +55,17 @@ static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2,
                           Oid **diff);
 static Oid     classIdGetDbId(Oid classId);
 static void shdepLockAndCheckObject(Oid classId, Oid objectId);
-static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
+static void shdepChangeDep(Relation sdepRel,
+                          Oid classid, Oid objid, int32 objsubid,
                           Oid refclassid, Oid refobjid,
                           SharedDependencyType deptype);
-static void shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId,
+static void shdepAddDependency(Relation sdepRel,
+                                  Oid classId, Oid objectId, int32 objsubId,
                                   Oid refclassId, Oid refobjId,
                                   SharedDependencyType deptype);
-static void shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId,
+static void shdepDropDependency(Relation sdepRel,
+                                       Oid classId, Oid objectId, int32 objsubId,
+                                       bool drop_subobjects,
                                        Oid refclassId, Oid refobjId,
                                        SharedDependencyType deptype);
 static void storeObjectDescription(StringInfo descs, objectType type,
@@ -107,6 +115,7 @@ recordSharedDependencyOn(ObjectAddress *depender,
                                                          sdepRel))
        {
                shdepAddDependency(sdepRel, depender->classId, depender->objectId,
+                                                  depender->objectSubId,
                                                   referenced->classId, referenced->objectId,
                                                   deptype);
        }
@@ -159,14 +168,15 @@ recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
  * locked.
  */
 static void
-shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
+shdepChangeDep(Relation sdepRel,
+                          Oid classid, Oid objid, int32 objsubid,
                           Oid refclassid, Oid refobjid,
                           SharedDependencyType deptype)
 {
        Oid                     dbid = classIdGetDbId(classid);
        HeapTuple       oldtup = NULL;
        HeapTuple       scantup;
-       ScanKeyData key[3];
+       ScanKeyData key[4];
        SysScanDesc scan;
 
        /*
@@ -190,9 +200,13 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
                                Anum_pg_shdepend_objid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(objid));
+       ScanKeyInit(&key[3],
+                               Anum_pg_shdepend_objsubid,
+                               BTEqualStrategyNumber, F_INT4EQ,
+                               Int32GetDatum(objsubid));
 
        scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
-                                                         SnapshotNow, 3, key);
+                                                         SnapshotNow, 4, key);
 
        while ((scantup = systable_getnext(scan)) != NULL)
        {
@@ -202,8 +216,8 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
                /* Caller screwed up if multiple matches */
                if (oldtup)
                        elog(ERROR,
-                                "multiple pg_shdepend entries for object %u/%u deptype %c",
-                                classid, objid, deptype);
+                          "multiple pg_shdepend entries for object %u/%u/%d deptype %c",
+                                classid, objid, objsubid, deptype);
                oldtup = heap_copytuple(scantup);
        }
 
@@ -235,11 +249,12 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
                Datum           values[Natts_pg_shdepend];
                bool            nulls[Natts_pg_shdepend];
 
-               memset(nulls, 0, sizeof(nulls));
+               memset(nulls, false, sizeof(nulls));
 
                values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
                values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
                values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);
+               values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid);
 
                values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
                values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
@@ -264,6 +279,9 @@ shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
  * changeDependencyOnOwner
  *
  * Update the shared dependencies to account for the new owner.
+ *
+ * Note: we don't need an objsubid argument because only whole objects
+ * have owners.
  */
 void
 changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
@@ -273,7 +291,8 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
        sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
 
        /* Adjust the SHARED_DEPENDENCY_OWNER entry */
-       shdepChangeDep(sdepRel, classId, objectId,
+       shdepChangeDep(sdepRel,
+                                  classId, objectId, 0,
                                   AuthIdRelationId, newOwnerId,
                                   SHARED_DEPENDENCY_OWNER);
 
@@ -296,7 +315,7 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
         * to make the various ALTER OWNER routines each know about it.
         *----------
         */
-       shdepDropDependency(sdepRel, classId, objectId,
+       shdepDropDependency(sdepRel, classId, objectId, 0, true,
                                                AuthIdRelationId, newOwnerId,
                                                SHARED_DEPENDENCY_ACL);
 
@@ -364,7 +383,7 @@ getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff)
  * updateAclDependencies
  *             Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
  *
- * classId, objectId: identify the object whose ACL this is
+ * classId, objectId, objsubId: identify the object whose ACL this is
  * ownerId: role owning the object
  * isGrant: are we adding or removing ACL entries?
  * noldmembers, oldmembers: array of roleids appearing in old ACL
@@ -384,7 +403,8 @@ getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff)
  * before return.
  */
 void
-updateAclDependencies(Oid classId, Oid objectId, Oid ownerId, bool isGrant,
+updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
+                                         Oid ownerId, bool isGrant,
                                          int noldmembers, Oid *oldmembers,
                                          int nnewmembers, Oid *newmembers)
 {
@@ -425,11 +445,12 @@ updateAclDependencies(Oid classId, Oid objectId, Oid ownerId, bool isGrant,
                                continue;
 
                        if (isGrant)
-                               shdepAddDependency(sdepRel, classId, objectId,
+                               shdepAddDependency(sdepRel, classId, objectId, objsubId,
                                                                   AuthIdRelationId, roleid,
                                                                   SHARED_DEPENDENCY_ACL);
                        else
-                               shdepDropDependency(sdepRel, classId, objectId,
+                               shdepDropDependency(sdepRel, classId, objectId, objsubId,
+                                                                       false,          /* exact match on objsubId */
                                                                        AuthIdRelationId, roleid,
                                                                        SHARED_DEPENDENCY_ACL);
                }
@@ -453,8 +474,14 @@ typedef struct
  * checkSharedDependencies
  *
  * Check whether there are shared dependency entries for a given shared
- * object.     Returns a string containing a newline-separated list of object
+ * object; return true if so.
+ *
+ * In addition, return a string containing a newline-separated list of object
  * descriptions that depend on the shared object, or NULL if none is found.
+ * We actually return two such strings; the "detail" result is suitable for
+ * returning to the client as an errdetail() string, and is limited in size.
+ * The "detail_log" string is potentially much longer, and should be emitted
+ * to the server log only.
  *
  * We can find three different kinds of dependencies: dependencies on objects
  * of the current database; dependencies on shared objects; and dependencies
@@ -464,28 +491,32 @@ typedef struct
  *
  * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early.
  */
-char *
-checkSharedDependencies(Oid classId, Oid objectId)
+bool
+checkSharedDependencies(Oid classId, Oid objectId,
+                                               char **detail_msg, char **detail_log_msg)
 {
        Relation        sdepRel;
        ScanKeyData key[2];
        SysScanDesc scan;
        HeapTuple       tup;
-       int                     totalDeps = 0;
-       int                     numLocalDeps = 0;
-       int                     numSharedDeps = 0;
+       int                     numReportedDeps = 0;
+       int                     numNotReportedDeps = 0;
+       int                     numNotReportedDbs = 0;
        List       *remDeps = NIL;
        ListCell   *cell;
        ObjectAddress object;
        StringInfoData descs;
+       StringInfoData alldescs;
 
        /*
-        * We try to limit the number of reported dependencies to something sane,
-        * both for the user's sake and to avoid blowing out memory.
+        * We limit the number of dependencies reported to the client to
+        * MAX_REPORTED_DEPS, since client software may not deal well with
+        * enormous error strings.      The server log always gets a full report.
         */
 #define MAX_REPORTED_DEPS 100
 
        initStringInfo(&descs);
+       initStringInfo(&alldescs);
 
        sdepRel = heap_open(SharedDependRelationId, AccessShareLock);
 
@@ -519,7 +550,7 @@ checkSharedDependencies(Oid classId, Oid objectId)
 
                object.classId = sdepForm->classid;
                object.objectId = sdepForm->objid;
-               object.objectSubId = 0;
+               object.objectSubId = sdepForm->objsubid;
 
                /*
                 * If it's a dependency local to this database or it's a shared
@@ -530,17 +561,29 @@ checkSharedDependencies(Oid classId, Oid objectId)
                 */
                if (sdepForm->dbid == MyDatabaseId)
                {
-                       numLocalDeps++;
-                       if (++totalDeps <= MAX_REPORTED_DEPS)
+                       if (numReportedDeps < MAX_REPORTED_DEPS)
+                       {
+                               numReportedDeps++;
                                storeObjectDescription(&descs, LOCAL_OBJECT, &object,
                                                                           sdepForm->deptype, 0);
+                       }
+                       else
+                               numNotReportedDeps++;
+                       storeObjectDescription(&alldescs, LOCAL_OBJECT, &object,
+                                                                  sdepForm->deptype, 0);
                }
                else if (sdepForm->dbid == InvalidOid)
                {
-                       numSharedDeps++;
-                       if (++totalDeps <= MAX_REPORTED_DEPS)
+                       if (numReportedDeps < MAX_REPORTED_DEPS)
+                       {
+                               numReportedDeps++;
                                storeObjectDescription(&descs, SHARED_OBJECT, &object,
                                                                           sdepForm->deptype, 0);
+                       }
+                       else
+                               numNotReportedDeps++;
+                       storeObjectDescription(&alldescs, SHARED_OBJECT, &object,
+                                                                  sdepForm->deptype, 0);
                }
                else
                {
@@ -570,7 +613,6 @@ checkSharedDependencies(Oid classId, Oid objectId)
                                dep->dbOid = sdepForm->dbid;
                                dep->count = 1;
                                remDeps = lappend(remDeps, dep);
-                               totalDeps++;
                        }
                }
        }
@@ -579,29 +621,9 @@ checkSharedDependencies(Oid classId, Oid objectId)
 
        heap_close(sdepRel, AccessShareLock);
 
-       if (totalDeps > MAX_REPORTED_DEPS)
-       {
-               /*
-                * Report seems unreasonably long, so reduce it to per-database info
-                *
-                * Note: we don't ever suppress per-database totals, which should be
-                * OK as long as there aren't too many databases ...
-                */
-               descs.len = 0;                  /* reset to empty */
-               descs.data[0] = '\0';
-
-               if (numLocalDeps > 0)
-               {
-                       appendStringInfo(&descs, _("%d objects in this database"),
-                                                        numLocalDeps);
-                       if (numSharedDeps > 0)
-                               appendStringInfoChar(&descs, '\n');
-               }
-               if (numSharedDeps > 0)
-                       appendStringInfo(&descs, _("%d shared objects"),
-                                                        numSharedDeps);
-       }
-
+       /*
+        * Summarize dependencies in remote databases.
+        */
        foreach(cell, remDeps)
        {
                remoteDep  *dep = lfirst(cell);
@@ -610,7 +632,15 @@ checkSharedDependencies(Oid classId, Oid objectId)
                object.objectId = dep->dbOid;
                object.objectSubId = 0;
 
-               storeObjectDescription(&descs, REMOTE_OBJECT, &object,
+               if (numReportedDeps < MAX_REPORTED_DEPS)
+               {
+                       numReportedDeps++;
+                       storeObjectDescription(&descs, REMOTE_OBJECT, &object,
+                                                                  SHARED_DEPENDENCY_INVALID, dep->count);
+               }
+               else
+                       numNotReportedDbs++;
+               storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
                                                           SHARED_DEPENDENCY_INVALID, dep->count);
        }
 
@@ -619,10 +649,29 @@ checkSharedDependencies(Oid classId, Oid objectId)
        if (descs.len == 0)
        {
                pfree(descs.data);
-               return NULL;
+               pfree(alldescs.data);
+               *detail_msg = *detail_log_msg = NULL;
+               return false;
        }
 
-       return descs.data;
+       if (numNotReportedDeps > 0)
+               appendStringInfo(&descs, ngettext("\nand %d other object "
+                                                                                 "(see server log for list)",
+                                                                                 "\nand %d other objects "
+                                                                                 "(see server log for list)",
+                                                                                 numNotReportedDeps),
+                                                numNotReportedDeps);
+       if (numNotReportedDbs > 0)
+               appendStringInfo(&descs, ngettext("\nand objects in %d other database "
+                                                                                 "(see server log for list)",
+                                                                          "\nand objects in %d other databases "
+                                                                                 "(see server log for list)",
+                                                                                 numNotReportedDbs),
+                                                numNotReportedDbs);
+
+       *detail_msg = descs.data;
+       *detail_log_msg = alldescs.data;
+       return true;
 }
 
 /*
@@ -729,7 +778,7 @@ dropDatabaseDependencies(Oid databaseId)
        systable_endscan(scan);
 
        /* Now delete all entries corresponding to the database itself */
-       shdepDropDependency(sdepRel, DatabaseRelationId, databaseId,
+       shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
                                                InvalidOid, InvalidOid,
                                                SHARED_DEPENDENCY_INVALID);
 
@@ -742,15 +791,19 @@ dropDatabaseDependencies(Oid databaseId)
  * Delete all pg_shdepend entries corresponding to an object that's being
  * dropped or modified.  The object is assumed to be either a shared object
  * or local to the current database (the classId tells us which).
+ *
+ * If objectSubId is zero, we are deleting a whole object, so get rid of
+ * pg_shdepend entries for subobjects as well.
  */
 void
-deleteSharedDependencyRecordsFor(Oid classId, Oid objectId)
+deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
 {
        Relation        sdepRel;
 
        sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
 
-       shdepDropDependency(sdepRel, classId, objectId,
+       shdepDropDependency(sdepRel, classId, objectId, objectSubId,
+                                               (objectSubId == 0),
                                                InvalidOid, InvalidOid,
                                                SHARED_DEPENDENCY_INVALID);
 
@@ -765,7 +818,8 @@ deleteSharedDependencyRecordsFor(Oid classId, Oid objectId)
  * locked.
  */
 static void
-shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId,
+shdepAddDependency(Relation sdepRel,
+                                  Oid classId, Oid objectId, int32 objsubId,
                                   Oid refclassId, Oid refobjId,
                                   SharedDependencyType deptype)
 {
@@ -788,6 +842,7 @@ shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId,
        values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
        values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
        values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
+       values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
 
        values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
        values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
@@ -809,20 +864,26 @@ shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId,
  *             Internal workhorse for deleting entries from pg_shdepend.
  *
  * We drop entries having the following properties:
- *     dependent object is the one identified by classId/objectId
+ *     dependent object is the one identified by classId/objectId/objsubId
  *     if refclassId isn't InvalidOid, it must match the entry's refclassid
  *     if refobjId isn't InvalidOid, it must match the entry's refobjid
  *     if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype
  *
+ * If drop_subobjects is true, we ignore objsubId and consider all entries
+ * matching classId/objectId.
+ *
  * sdepRel must be the pg_shdepend relation, already opened and suitably
  * locked.
  */
 static void
-shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId,
+shdepDropDependency(Relation sdepRel,
+                                       Oid classId, Oid objectId, int32 objsubId,
+                                       bool drop_subobjects,
                                        Oid refclassId, Oid refobjId,
                                        SharedDependencyType deptype)
 {
-       ScanKeyData key[3];
+       ScanKeyData key[4];
+       int                     nkeys;
        SysScanDesc scan;
        HeapTuple       tup;
 
@@ -839,9 +900,19 @@ shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId,
                                Anum_pg_shdepend_objid,
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(objectId));
+       if (drop_subobjects)
+               nkeys = 3;
+       else
+       {
+               ScanKeyInit(&key[3],
+                                       Anum_pg_shdepend_objsubid,
+                                       BTEqualStrategyNumber, F_INT4EQ,
+                                       Int32GetDatum(objsubId));
+               nkeys = 4;
+       }
 
        scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
-                                                         SnapshotNow, 3, key);
+                                                         SnapshotNow, nkeys, key);
 
        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
@@ -869,30 +940,17 @@ shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId,
  * Get the database Id that should be used in pg_shdepend, given the OID
  * of the catalog containing the object.  For shared objects, it's 0
  * (InvalidOid); for all other objects, it's the current database Id.
- *
- * XXX it's awfully tempting to hard-wire this instead of doing a syscache
- * lookup ... but resist the temptation, unless you can prove it's a
- * bottleneck.
  */
 static Oid
 classIdGetDbId(Oid classId)
 {
        Oid                     dbId;
-       HeapTuple       tup;
 
-       tup = SearchSysCache(RELOID,
-                                                ObjectIdGetDatum(classId),
-                                                0, 0, 0);
-       if (!HeapTupleIsValid(tup))
-               elog(ERROR, "cache lookup failed for relation %u", classId);
-
-       if (((Form_pg_class) GETSTRUCT(tup))->relisshared)
+       if (IsSharedRelation(classId))
                dbId = InvalidOid;
        else
                dbId = MyDatabaseId;
 
-       ReleaseSysCache(tup);
-
        return dbId;
 }
 
@@ -991,7 +1049,10 @@ storeObjectDescription(StringInfo descs, objectType type,
 
                case REMOTE_OBJECT:
                        /* translator: %s will always be "database %s" */
-                       appendStringInfo(descs, _("%d objects in %s"), count, objdesc);
+                       appendStringInfo(descs, ngettext("%d object in %s",
+                                                                                        "%d objects in %s",
+                                                                                        count),
+                                                        count, objdesc);
                        break;
 
                default:
@@ -1054,15 +1115,28 @@ isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
  *
  * Drop the objects owned by any one of the given RoleIds.     If a role has
  * access to an object, the grant will be removed as well (but the object
- * will not, of course.)
+ * will not, of course).
+ *
+ * We can revoke grants immediately while doing the scan, but drops are
+ * saved up and done all at once with performMultipleDeletions.  This
+ * is necessary so that we don't get failures from trying to delete
+ * interdependent objects in the wrong order.
  */
 void
 shdepDropOwned(List *roleids, DropBehavior behavior)
 {
        Relation        sdepRel;
        ListCell   *cell;
+       ObjectAddresses *deleteobjs;
+
+       deleteobjs = new_object_addresses();
 
-       sdepRel = heap_open(SharedDependRelationId, AccessExclusiveLock);
+       /*
+        * We don't need this strong a lock here, but we'll call routines that
+        * acquire RowExclusiveLock.  Better get that right now to avoid potential
+        * deadlock failures.
+        */
+       sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
 
        /*
         * For each role, find the dependent objects and drop them using the
@@ -1106,17 +1180,15 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                while ((tuple = systable_getnext(scan)) != NULL)
                {
                        Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
+                       InternalGrant istmt;
+                       ObjectAddress obj;
 
-                       /* We only operate on objects on the current database */
+                       /* We only operate on objects in the current database */
                        if (sdepForm->dbid != MyDatabaseId)
                                continue;
 
                        switch (sdepForm->deptype)
                        {
-                                       ObjectAddress obj;
-                                       GrantObjectType objtype;
-                                       InternalGrant istmt;
-
                                        /* Shouldn't happen */
                                case SHARED_DEPENDENCY_PIN:
                                case SHARED_DEPENDENCY_INVALID:
@@ -1126,25 +1198,9 @@ 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);
+                                                       /* it's OK to use RELATION for a sequence */
+                                                       istmt.objtype = ACL_OBJECT_RELATION;
                                                        break;
-                                               }
                                                case DatabaseRelationId:
                                                        istmt.objtype = ACL_OBJECT_DATABASE;
                                                        break;
@@ -1163,14 +1219,13 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                                                default:
                                                        elog(ERROR, "unexpected object type %d",
                                                                 sdepForm->classid);
-                                                       /* keep compiler quiet */
-                                                       objtype = (GrantObjectType) 0;
                                                        break;
                                        }
                                        istmt.is_grant = false;
                                        istmt.objects = list_make1_oid(sdepForm->objid);
                                        istmt.all_privs = true;
                                        istmt.privileges = ACL_NO_RIGHTS;
+                                       istmt.col_privs = NIL;
                                        istmt.grantees = list_make1_oid(roleid);
                                        istmt.grant_option = false;
                                        istmt.behavior = DROP_CASCADE;
@@ -1178,20 +1233,11 @@ 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 deletion below */
                                        obj.classId = sdepForm->classid;
                                        obj.objectId = sdepForm->objid;
-                                       obj.objectSubId = 0;
-                                       performDeletion(&obj, behavior);
+                                       obj.objectSubId = sdepForm->objsubid;
+                                       add_exact_object_address(&obj, deleteobjs);
                                        break;
                        }
                }
@@ -1199,7 +1245,12 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                systable_endscan(scan);
        }
 
-       heap_close(sdepRel, AccessExclusiveLock);
+       /* the dependency mechanism does the actual work */
+       performMultipleDeletions(deleteobjs, behavior);
+
+       heap_close(sdepRel, RowExclusiveLock);
+
+       free_object_addresses(deleteobjs);
 }
 
 /*
@@ -1214,7 +1265,12 @@ shdepReassignOwned(List *roleids, Oid newrole)
        Relation        sdepRel;
        ListCell   *cell;
 
-       sdepRel = heap_open(SharedDependRelationId, AccessShareLock);
+       /*
+        * We don't need this strong a lock here, but we'll call routines that
+        * acquire RowExclusiveLock.  Better get that right now to avoid potential
+        * deadlock problems.
+        */
+       sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
 
        foreach(cell, roleids)
        {
@@ -1260,7 +1316,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
                {
                        Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
 
-                       /* We only operate on objects on the current database */
+                       /* We only operate on objects in the current database */
                        if (sdepForm->dbid != MyDatabaseId)
                                continue;
 
@@ -1272,15 +1328,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
                        if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
                                continue;
 
-                       /*
-                        * If there's a regular (non-shared) dependency on this object
-                        * marked with DEPENDENCY_INTERNAL, skip this object.  We will
-                        * alter the referencer object instead.
-                        */
-                       if (objectIsInternalDependency(sdepForm->classid, sdepForm->objid))
-                               continue;
-
-                       /* Issue the appropiate ALTER OWNER call */
+                       /* Issue the appropriate ALTER OWNER call */
                        switch (sdepForm->classid)
                        {
                                case ConversionRelationId:
@@ -1288,7 +1336,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
                                        break;
 
                                case TypeRelationId:
-                                       AlterTypeOwnerInternal(sdepForm->objid, newrole);
+                                       AlterTypeOwnerInternal(sdepForm->objid, newrole, true);
                                        break;
 
                                case OperatorRelationId:
@@ -1300,13 +1348,23 @@ shdepReassignOwned(List *roleids, Oid newrole)
                                        break;
 
                                case RelationRelationId:
-                                       ATExecChangeOwner(sdepForm->objid, newrole, false);
+
+                                       /*
+                                        * Pass recursing = true so that we don't fail on indexes,
+                                        * owned sequences, etc when we happen to visit them
+                                        * before their parent table.
+                                        */
+                                       ATExecChangeOwner(sdepForm->objid, newrole, true);
                                        break;
 
                                case ProcedureRelationId:
                                        AlterFunctionOwner_oid(sdepForm->objid, newrole);
                                        break;
 
+                               case LanguageRelationId:
+                                       AlterLanguageOwner_oid(sdepForm->objid, newrole);
+                                       break;
+
                                default:
                                        elog(ERROR, "unexpected classid %d", sdepForm->classid);
                                        break;
@@ -1318,5 +1376,5 @@ shdepReassignOwned(List *roleids, Oid newrole)
                systable_endscan(scan);
        }
 
-       heap_close(sdepRel, AccessShareLock);
+       heap_close(sdepRel, RowExclusiveLock);
 }