Re: DROP OWNED BY fails to clean out pg_init_privs grants - Mailing list pgsql-hackers

From Tom Lane
Subject Re: DROP OWNED BY fails to clean out pg_init_privs grants
Date
Msg-id 2597398.1718408781@sss.pgh.pa.us
Whole thread Raw
In response to Re: DROP OWNED BY fails to clean out pg_init_privs grants  (Robert Haas <robertmhaas@gmail.com>)
Responses Re: DROP OWNED BY fails to clean out pg_init_privs grants
Re: DROP OWNED BY fails to clean out pg_init_privs grants
List pgsql-hackers
Robert Haas <robertmhaas@gmail.com> writes:
> I think the only thing we absolutely have to fix here is the dangling
> ACL references.

Here's a draft patch that takes care of Hannu's example, and I think
it fixes other potential dangling-reference scenarios too.

I'm not sure whether I like the direction this is going, but I do
think we may not be able to do a lot more than this for v17.

The core change is to install SHARED_DEPENDENCY_INITACL entries in
pg_shdepend for all references to non-pinned roles in pg_init_privs,
whether they are the object's owner or not.  Doing that ensures that
we can't drop a role that is still referenced there, and it provides
a basis for shdepDropOwned and shdepReassignOwned to take some kind
of action for such references.

The semantics I've implemented on top of that are:

* ALTER OWNER does not touch pg_init_privs entries.

* REASSIGN OWNED replaces pg_init_privs references with the new
role, whether the references are as grantor or grantee.

* DROP OWNED removes pg_init_privs mentions of the doomed role
(as grantor or grantee), removing the pg_init_privs entry
altogether if it goes to zero clauses.  (This is what happened
already, but only if if a SHARED_DEPENDENCY_INITACL entry existed.)

I'm not terribly thrilled with this, because it's still possible
to get into a state where a pg_init_privs entry is based on
an owning role that's no longer the owner: you just have to use
ALTER OWNER directly rather than via REASSIGN OWNED.  While
I don't think the backend has much problem with that, it probably
will confuse pg_dump to some extent.  However, such cases are
going to confuse pg_dump anyway for reasons discussed upthread,
namely that we don't really support dump/restore of extensions
where not all the objects are owned by the extension owner.
I'm content to leave that in the pile of unfinished work for now.

An alternative definition could be that ALTER OWNER also replaces
old role with new in pg_init_privs entries.  That would reduce
the surface for confusing pg_dump a little bit, but I don't think
that I like it better, for two reasons:

* ALTER OWNER would have to probe pg_init_acl for potential
entries every time, which would be wasted work for most ALTERs.

* This gets away from the notion that pg_init_privs should be
a historical record of the state that existed at the end of CREATE
EXTENSION.  Now, maybe that notion is unworkable anyway, but
I don't want to let go of it before we're sure about that.

A couple of more-minor points for review:

* As this stands, updateInitAclDependencies() no longer pays any
attention to its ownerId argument, and in one place I depend on
that to skip doing a rather expensive lookup of the current object
owner.  Perhaps we should remove that argument altogether, and
in consequence simplify some other callers too?  However, that
would only help much if we were willing to revert 534287403's
changes to pass the object's owner ID to recordExtensionInitPriv,
which I'm hesitant to do because I suspect we'll end up wanting
to record the owner ID explicitly in pg_init_privs entries.
On the third hand, maybe we'll never do that, so perhaps we should
revert those changes for now; some of them add nontrivial lookup
costs.

* In shdepReassignOwned, I refactored to move the switch on
sdepForm->classid into a new subroutine.  We could have left
it where it is, but it would need a couple more tab stops of
indentation which felt like too much.  It's in the eye of
the beholder though.

Comments?

            regards, tom lane

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 2f52e70b48..a63cc71efa 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7182,9 +7182,6 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
        The referenced object (which must be a role) is mentioned in a
        <link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link>
        entry for the dependent object.
-       (A <symbol>SHARED_DEPENDENCY_INITACL</symbol> entry is not made for
-       the owner of the object, since the owner will have
-       a <symbol>SHARED_DEPENDENCY_OWNER</symbol> entry anyway.)
       </para>
      </listitem>
     </varlistentry>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 143876b77f..ad61e2e4a1 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -4846,6 +4846,124 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
     table_close(relation, RowExclusiveLock);
 }

+/*
+ * ReplaceRoleInInitPriv
+ *
+ * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
+ */
+void
+ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
+                      Oid classid, Oid objid, int32 objsubid)
+{
+    Relation    rel;
+    ScanKeyData key[3];
+    SysScanDesc scan;
+    HeapTuple    oldtuple;
+    Datum        oldAclDatum;
+    bool        isNull;
+    Acl           *old_acl;
+    Acl           *new_acl;
+    HeapTuple    newtuple;
+    int            noldmembers;
+    int            nnewmembers;
+    Oid           *oldmembers;
+    Oid           *newmembers;
+
+    /* Search for existing pg_init_privs entry for the target object. */
+    rel = table_open(InitPrivsRelationId, RowExclusiveLock);
+
+    ScanKeyInit(&key[0],
+                Anum_pg_init_privs_objoid,
+                BTEqualStrategyNumber, F_OIDEQ,
+                ObjectIdGetDatum(objid));
+    ScanKeyInit(&key[1],
+                Anum_pg_init_privs_classoid,
+                BTEqualStrategyNumber, F_OIDEQ,
+                ObjectIdGetDatum(classid));
+    ScanKeyInit(&key[2],
+                Anum_pg_init_privs_objsubid,
+                BTEqualStrategyNumber, F_INT4EQ,
+                Int32GetDatum(objsubid));
+
+    scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
+                              NULL, 3, key);
+
+    /* There should exist only one entry or none. */
+    oldtuple = systable_getnext(scan);
+
+    if (!HeapTupleIsValid(oldtuple))
+    {
+        /*
+         * Hmm, why are we here if there's no entry?  But pack up and go away
+         * quietly.
+         */
+        systable_endscan(scan);
+        table_close(rel, RowExclusiveLock);
+        return;
+    }
+
+    /* Get a writable copy of the existing ACL. */
+    oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
+                               RelationGetDescr(rel), &isNull);
+    if (isNull)
+    {
+        /* Nothing needs to be changed; pack up and go away quietly. */
+        systable_endscan(scan);
+        table_close(rel, RowExclusiveLock);
+        return;
+    }
+    old_acl = DatumGetAclPCopy(oldAclDatum);
+
+    /*
+     * Generate new ACL.  This usage of aclnewowner is a bit off-label when
+     * oldroleid isn't the owner; but it does the job fine.
+     */
+    new_acl = aclnewowner(old_acl, oldroleid, newroleid);
+
+    /*
+     * If we end with an empty ACL, delete the pg_init_privs entry.  (That
+     * probably can't happen here, but we may as well cover the case.)
+     */
+    if (new_acl == NULL || ACL_NUM(new_acl) == 0)
+    {
+        CatalogTupleDelete(rel, &oldtuple->t_self);
+    }
+    else
+    {
+        Datum        values[Natts_pg_init_privs] = {0};
+        bool        nulls[Natts_pg_init_privs] = {0};
+        bool        replaces[Natts_pg_init_privs] = {0};
+
+        /* Update existing entry. */
+        values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
+        replaces[Anum_pg_init_privs_initprivs - 1] = true;
+
+        newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
+                                     values, nulls, replaces);
+        CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
+    }
+
+    /*
+     * Update the shared dependency ACL info.  We rely on the knowledge that
+     * updateInitAclDependencies doesn't really pay attention to its ownerId
+     * argument, so it doesn't matter whether that's accurate or not.
+     */
+    noldmembers = aclmembers(old_acl, &oldmembers);
+    nnewmembers = aclmembers(new_acl, &newmembers);
+
+    updateInitAclDependencies(classid, objid, objsubid,
+                              oldroleid,
+                              noldmembers, oldmembers,
+                              nnewmembers, newmembers);
+
+    systable_endscan(scan);
+
+    /* prevent error when processing objects multiple times */
+    CommandCounterIncrement();
+
+    table_close(rel, RowExclusiveLock);
+}
+
 /*
  * RemoveRoleFromInitPriv
  *
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 20bcfd779b..d1b005d4ff 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -103,6 +103,9 @@ static void storeObjectDescription(StringInfo descs,
                                    ObjectAddress *object,
                                    SharedDependencyType deptype,
                                    int count);
+static void shdepReassignOwned_Owner(Form_pg_shdepend sdepForm, Oid newrole);
+static void shdepReassignOwned_InitAcl(Form_pg_shdepend sdepForm,
+                                       Oid oldrole, Oid newrole);


 /*
@@ -345,10 +348,11 @@ changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
                         AuthIdRelationId, newOwnerId,
                         SHARED_DEPENDENCY_ACL);

-    /* The same applies to SHARED_DEPENDENCY_INITACL */
-    shdepDropDependency(sdepRel, classId, objectId, 0, true,
-                        AuthIdRelationId, newOwnerId,
-                        SHARED_DEPENDENCY_INITACL);
+    /*
+     * However, nothing need be done about SHARED_DEPENDENCY_INITACL entries,
+     * since those exist whether or not the role is the object's owner, and
+     * ALTER OWNER does not modify the underlying pg_init_privs entry.
+     */

     table_close(sdepRel, RowExclusiveLock);
 }
@@ -501,6 +505,8 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
  *
  * Exactly like updateAclDependencies, except we are considering a
  * pg_init_privs ACL for the specified object.
+ *
+ * Note: with the current semantics, ownerId isn't actually consulted.
  */
 void
 updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId,
@@ -542,11 +548,13 @@ updateAclDependenciesWorker(Oid classId, Oid objectId, int32 objsubId,
             Oid            roleid = newmembers[i];

             /*
-             * Skip the owner: he has an OWNER shdep entry instead. (This is
-             * not just a space optimization; it makes ALTER OWNER easier. See
-             * notes in changeDependencyOnOwner.)
+             * For SHARED_DEPENDENCY_ACL entries, skip the owner: she has an
+             * OWNER shdep entry instead.  (This is not just a space
+             * optimization; it makes ALTER OWNER easier.  See notes in
+             * changeDependencyOnOwner.)  But for INITACL entries, we record
+             * the owner too.
              */
-            if (roleid == ownerId)
+            if (deptype == SHARED_DEPENDENCY_ACL && roleid == ownerId)
                 continue;

             /* Skip pinned roles; they don't need dependency entries */
@@ -563,8 +571,8 @@ updateAclDependenciesWorker(Oid classId, Oid objectId, int32 objsubId,
         {
             Oid            roleid = oldmembers[i];

-            /* Skip the owner, same as above */
-            if (roleid == ownerId)
+            /* Skip the owner for ACL entries, same as above */
+            if (deptype == SHARED_DEPENDENCY_ACL && roleid == ownerId)
                 continue;

             /* Skip pinned roles */
@@ -1476,6 +1484,13 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
                     }
                     break;
                 case SHARED_DEPENDENCY_INITACL:
+
+                    /*
+                     * Any mentions of the role that remain in pg_init_privs
+                     * entries are just dropped.  This is the same policy as
+                     * we apply to regular ACLs.
+                     */
+
                     /* Shouldn't see a role grant here */
                     Assert(sdepForm->classid != AuthMemRelationId);
                     RemoveRoleFromInitPriv(roleid,
@@ -1577,12 +1592,8 @@ shdepReassignOwned(List *roleids, Oid newrole)
                 sdepForm->dbid != InvalidOid)
                 continue;

-            /* We leave non-owner dependencies alone */
-            if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
-                continue;
-
             /*
-             * The various ALTER OWNER routines tend to leak memory in
+             * The various DDL routines called here tend to leak memory in
              * CurrentMemoryContext.  That's not a problem when they're only
              * called once per command; but in this usage where we might be
              * touching many objects, it can amount to a serious memory leak.
@@ -1593,81 +1604,23 @@ shdepReassignOwned(List *roleids, Oid newrole)
                                         ALLOCSET_DEFAULT_SIZES);
             oldcxt = MemoryContextSwitchTo(cxt);

-            /* Issue the appropriate ALTER OWNER call */
-            switch (sdepForm->classid)
+            /* Perform the appropriate processing */
+            switch (sdepForm->deptype)
             {
-                case TypeRelationId:
-                    AlterTypeOwner_oid(sdepForm->objid, newrole, true);
-                    break;
-
-                case NamespaceRelationId:
-                    AlterSchemaOwner_oid(sdepForm->objid, newrole);
-                    break;
-
-                case RelationRelationId:
-
-                    /*
-                     * 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, AccessExclusiveLock);
-                    break;
-
-                case DefaultAclRelationId:
-
-                    /*
-                     * Ignore default ACLs; they should be handled by DROP
-                     * OWNED, not REASSIGN OWNED.
-                     */
-                    break;
-
-                case UserMappingRelationId:
-                    /* ditto */
-                    break;
-
-                case ForeignServerRelationId:
-                    AlterForeignServerOwner_oid(sdepForm->objid, newrole);
-                    break;
-
-                case ForeignDataWrapperRelationId:
-                    AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
-                    break;
-
-                case EventTriggerRelationId:
-                    AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
-                    break;
-
-                case PublicationRelationId:
-                    AlterPublicationOwner_oid(sdepForm->objid, newrole);
+                case SHARED_DEPENDENCY_OWNER:
+                    shdepReassignOwned_Owner(sdepForm, newrole);
                     break;
-
-                case SubscriptionRelationId:
-                    AlterSubscriptionOwner_oid(sdepForm->objid, newrole);
+                case SHARED_DEPENDENCY_INITACL:
+                    shdepReassignOwned_InitAcl(sdepForm, roleid, newrole);
                     break;
-
-                    /* Generic alter owner cases */
-                case CollationRelationId:
-                case ConversionRelationId:
-                case OperatorRelationId:
-                case ProcedureRelationId:
-                case LanguageRelationId:
-                case LargeObjectRelationId:
-                case OperatorFamilyRelationId:
-                case OperatorClassRelationId:
-                case ExtensionRelationId:
-                case StatisticExtRelationId:
-                case TableSpaceRelationId:
-                case DatabaseRelationId:
-                case TSConfigRelationId:
-                case TSDictionaryRelationId:
-                    AlterObjectOwner_internal(sdepForm->classid,
-                                              sdepForm->objid,
-                                              newrole);
+                case SHARED_DEPENDENCY_ACL:
+                case SHARED_DEPENDENCY_POLICY:
+                case SHARED_DEPENDENCY_TABLESPACE:
+                    /* Nothing to do for these entry types */
                     break;
-
                 default:
-                    elog(ERROR, "unexpected classid %u", sdepForm->classid);
+                    elog(ERROR, "unrecognized dependency type: %d",
+                         (int) sdepForm->deptype);
                     break;
             }

@@ -1684,3 +1637,123 @@ shdepReassignOwned(List *roleids, Oid newrole)

     table_close(sdepRel, RowExclusiveLock);
 }
+
+/*
+ * shdepReassignOwned_Owner
+ *
+ * shdepReassignOwned's processing of SHARED_DEPENDENCY_OWNER entries
+ */
+static void
+shdepReassignOwned_Owner(Form_pg_shdepend sdepForm, Oid newrole)
+{
+    /* Issue the appropriate ALTER OWNER call */
+    switch (sdepForm->classid)
+    {
+        case TypeRelationId:
+            AlterTypeOwner_oid(sdepForm->objid, newrole, true);
+            break;
+
+        case NamespaceRelationId:
+            AlterSchemaOwner_oid(sdepForm->objid, newrole);
+            break;
+
+        case RelationRelationId:
+
+            /*
+             * 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, AccessExclusiveLock);
+            break;
+
+        case DefaultAclRelationId:
+
+            /*
+             * Ignore default ACLs; they should be handled by DROP OWNED, not
+             * REASSIGN OWNED.
+             */
+            break;
+
+        case UserMappingRelationId:
+            /* ditto */
+            break;
+
+        case ForeignServerRelationId:
+            AlterForeignServerOwner_oid(sdepForm->objid, newrole);
+            break;
+
+        case ForeignDataWrapperRelationId:
+            AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
+            break;
+
+        case EventTriggerRelationId:
+            AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
+            break;
+
+        case PublicationRelationId:
+            AlterPublicationOwner_oid(sdepForm->objid, newrole);
+            break;
+
+        case SubscriptionRelationId:
+            AlterSubscriptionOwner_oid(sdepForm->objid, newrole);
+            break;
+
+            /* Generic alter owner cases */
+        case CollationRelationId:
+        case ConversionRelationId:
+        case OperatorRelationId:
+        case ProcedureRelationId:
+        case LanguageRelationId:
+        case LargeObjectRelationId:
+        case OperatorFamilyRelationId:
+        case OperatorClassRelationId:
+        case ExtensionRelationId:
+        case StatisticExtRelationId:
+        case TableSpaceRelationId:
+        case DatabaseRelationId:
+        case TSConfigRelationId:
+        case TSDictionaryRelationId:
+            AlterObjectOwner_internal(sdepForm->classid,
+                                      sdepForm->objid,
+                                      newrole);
+            break;
+
+        default:
+            elog(ERROR, "unexpected classid %u", sdepForm->classid);
+            break;
+    }
+}
+
+/*
+ * shdepReassignOwned_InitAcl
+ *
+ * shdepReassignOwned's processing of SHARED_DEPENDENCY_INITACL entries
+ */
+static void
+shdepReassignOwned_InitAcl(Form_pg_shdepend sdepForm, Oid oldrole, Oid newrole)
+{
+    /*
+     * Currently, REASSIGN OWNED replaces mentions of oldrole with newrole in
+     * pg_init_privs entries, just as it does in the object's regular ACL.
+     * This is less than ideal, since pg_init_privs ought to retain a
+     * historical record of the situation at the end of CREATE EXTENSION.
+     * However, there are two big stumbling blocks to doing something
+     * different:
+     *
+     * 1. If we don't replace the references, what is to happen if the old
+     * role gets dropped?  (DROP OWNED's current answer is to just delete the
+     * pg_init_privs entry, which is surely ahistorical.)
+     *
+     * 2. It's unlikely that pg_dump will cope nicely with pg_init_privs
+     * entries that are based on a different owner than the object now has ---
+     * the more so given that pg_init_privs doesn't record the original owner
+     * explicitly.  (This problem actually exists anyway given that a bare
+     * ALTER OWNER won't update pg_init_privs, but we don't need REASSIGN
+     * OWNED making it worse.)
+     */
+    ReplaceRoleInInitPriv(oldrole, newrole,
+                          sdepForm->classid,
+                          sdepForm->objid,
+                          sdepForm->objsubid);
+}
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index dc10b4a483..d7b39140b3 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1091,6 +1091,12 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip,
  * The result is a modified copy; the input object is not changed.
  *
  * NB: caller is responsible for having detoasted the input ACL, if needed.
+ *
+ * Note: the name of this function is a bit of a misnomer, since it will
+ * happily make the specified role substitution whether the old role is
+ * really the owner of the parent object or merely mentioned in its ACL.
+ * But the vast majority of callers use it in connection with ALTER OWNER
+ * operations, so we'll keep the name.
  */
 Acl *
 aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 7eee66f810..aca0b0b6fe 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -57,10 +57,10 @@ typedef enum DependencyType
  * one or the other, but not both, of these dependency types.)
  *
  * (c) a SHARED_DEPENDENCY_INITACL entry means that the referenced object is
- * a role mentioned in a pg_init_privs entry for the dependent object.  The
- * referenced object must be a pg_authid entry.  (SHARED_DEPENDENCY_INITACL
- * entries are not created for the owner of an object; hence two objects may
- * be linked by one or the other, but not both, of these dependency types.)
+ * a role mentioned in a pg_init_privs entry for the dependent object.
+ * The referenced object must be a pg_authid entry.  (Unlike the case for
+ * SHARED_DEPENDENCY_ACL, we make an entry for such a role whether or not
+ * it is the object's owner.)
  *
  * (d) a SHARED_DEPENDENCY_POLICY entry means that the referenced object is
  * a role mentioned in a policy object.  The referenced object must be a
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 1a554c6699..731d84b2a9 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -276,6 +276,8 @@ extern void aclcheck_error_type(AclResult aclerr, Oid typeOid);

 extern void recordExtObjInitPriv(Oid objoid, Oid classoid);
 extern void removeExtObjInitPriv(Oid objoid, Oid classoid);
+extern void ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
+                                  Oid classid, Oid objid, int32 objsubid);
 extern void RemoveRoleFromInitPriv(Oid roleid,
                                    Oid classid, Oid objid, int32 objsubid);

diff --git a/src/test/modules/test_pg_dump/expected/test_pg_dump.out
b/src/test/modules/test_pg_dump/expected/test_pg_dump.out
index 3cd7db97aa..3536d636d8 100644
--- a/src/test/modules/test_pg_dump/expected/test_pg_dump.out
+++ b/src/test/modules/test_pg_dump/expected/test_pg_dump.out
@@ -283,3 +283,308 @@ SELECT * FROM pg_init_privs WHERE privtype = 'e';
 --------+----------+----------+----------+-----------
 (0 rows)

+CREATE ROLE regress_dump_test_role;
+CREATE ROLE regress_dump_test_super SUPERUSER;
+SET ROLE regress_dump_test_super;
+CREATE EXTENSION test_pg_dump;
+RESET ROLE;
+-- Substitute for current user's name to keep test output consistent
+SELECT s.obj,
+  CASE WHEN a.grantor::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantor::regrole::name END,
+  CASE WHEN a.grantee::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantee::regrole::name END,
+  a.privilege_type, a.is_grantable
+FROM
+  (SELECT pg_describe_object(classoid,objoid,objsubid) COLLATE "C" AS obj, initprivs
+   FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1) s,
+  aclexplode(s.initprivs) a;
+                        obj                         |         grantor         |         grantee         |
privilege_type| is_grantable  

+----------------------------------------------------+-------------------------+-------------------------+----------------+--------------
+ column col1 of table regress_pg_dump_table         | regress_dump_test_super | -                       | SELECT
 | f 
+ function regress_pg_dump_schema.test_agg(smallint) | regress_dump_test_super | -                       | EXECUTE
 | f 
+ function regress_pg_dump_schema.test_agg(smallint) | regress_dump_test_super | regress_dump_test_super | EXECUTE
 | f 
+ function regress_pg_dump_schema.test_agg(smallint) | regress_dump_test_super | regress_dump_test_role  | EXECUTE
 | f 
+ function regress_pg_dump_schema.test_func()        | regress_dump_test_super | -                       | EXECUTE
 | f 
+ function regress_pg_dump_schema.test_func()        | regress_dump_test_super | regress_dump_test_super | EXECUTE
 | f 
+ function regress_pg_dump_schema.test_func()        | regress_dump_test_super | regress_dump_test_role  | EXECUTE
 | f 
+ function wgo_then_no_access()                      | regress_dump_test_super | -                       | EXECUTE
 | f 
+ function wgo_then_no_access()                      | regress_dump_test_super | regress_dump_test_super | EXECUTE
 | f 
+ function wgo_then_no_access()                      | regress_dump_test_super | pg_signal_backend       | EXECUTE
 | t 
+ sequence regress_pg_dump_schema.test_seq           | regress_dump_test_super | regress_dump_test_super | SELECT
 | f 
+ sequence regress_pg_dump_schema.test_seq           | regress_dump_test_super | regress_dump_test_super | UPDATE
 | f 
+ sequence regress_pg_dump_schema.test_seq           | regress_dump_test_super | regress_dump_test_super | USAGE
 | f 
+ sequence regress_pg_dump_schema.test_seq           | regress_dump_test_super | regress_dump_test_role  | USAGE
 | f 
+ sequence regress_pg_dump_seq                       | regress_dump_test_super | regress_dump_test_super | SELECT
 | f 
+ sequence regress_pg_dump_seq                       | regress_dump_test_super | regress_dump_test_super | UPDATE
 | f 
+ sequence regress_pg_dump_seq                       | regress_dump_test_super | regress_dump_test_super | USAGE
 | f 
+ sequence regress_pg_dump_seq                       | regress_dump_test_super | regress_dump_test_role  | USAGE
 | f 
+ sequence regress_seq_dumpable                      | regress_dump_test_super | regress_dump_test_super | SELECT
 | f 
+ sequence regress_seq_dumpable                      | regress_dump_test_super | regress_dump_test_super | UPDATE
 | f 
+ sequence regress_seq_dumpable                      | regress_dump_test_super | regress_dump_test_super | USAGE
 | f 
+ sequence regress_seq_dumpable                      | regress_dump_test_super | -                       | SELECT
 | f 
+ sequence wgo_then_regular                          | regress_dump_test_super | regress_dump_test_super | SELECT
 | f 
+ sequence wgo_then_regular                          | regress_dump_test_super | regress_dump_test_super | UPDATE
 | f 
+ sequence wgo_then_regular                          | regress_dump_test_super | regress_dump_test_super | USAGE
 | f 
+ sequence wgo_then_regular                          | regress_dump_test_super | pg_signal_backend       | SELECT
 | f 
+ sequence wgo_then_regular                          | regress_dump_test_super | pg_signal_backend       | UPDATE
 | t 
+ sequence wgo_then_regular                          | regress_dump_test_super | pg_signal_backend       | USAGE
 | t 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | INSERT
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | SELECT
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | UPDATE
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | DELETE
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | TRUNCATE
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | REFERENCES
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | TRIGGER
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_super | MAINTAIN
 | f 
+ table regress_pg_dump_schema.test_table            | regress_dump_test_super | regress_dump_test_role  | SELECT
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | INSERT
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | SELECT
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | UPDATE
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | DELETE
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | TRUNCATE
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | REFERENCES
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | TRIGGER
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_super | MAINTAIN
 | f 
+ table regress_pg_dump_table                        | regress_dump_test_super | regress_dump_test_role  | SELECT
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | INSERT
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | SELECT
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | UPDATE
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | DELETE
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | TRUNCATE
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | REFERENCES
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | TRIGGER
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | regress_dump_test_super | MAINTAIN
 | f 
+ table regress_table_dumpable                       | regress_dump_test_super | -                       | SELECT
 | f 
+ type regress_pg_dump_schema.test_type              | regress_dump_test_super | -                       | USAGE
 | f 
+ type regress_pg_dump_schema.test_type              | regress_dump_test_super | regress_dump_test_super | USAGE
 | f 
+ type regress_pg_dump_schema.test_type              | regress_dump_test_super | regress_dump_test_role  | USAGE
 | f 
+(58 rows)
+
+SELECT pg_describe_object(classid,objid,objsubid) COLLATE "C" AS obj,
+  pg_describe_object(refclassid,refobjid,0) AS refobj,
+  deptype
+  FROM pg_shdepend JOIN pg_database d ON dbid = d.oid
+  WHERE d.datname = current_database()
+  ORDER BY 1, 2, 3;
+                        obj                         |            refobj            | deptype
+----------------------------------------------------+------------------------------+---------
+ column col1 of table regress_pg_dump_table         | role regress_dump_test_super | i
+ extension test_pg_dump                             | role regress_dump_test_super | o
+ function regress_pg_dump_schema.test_agg(smallint) | role regress_dump_test_role  | a
+ function regress_pg_dump_schema.test_agg(smallint) | role regress_dump_test_role  | i
+ function regress_pg_dump_schema.test_agg(smallint) | role regress_dump_test_super | i
+ function regress_pg_dump_schema.test_agg(smallint) | role regress_dump_test_super | o
+ function regress_pg_dump_schema.test_func()        | role regress_dump_test_role  | a
+ function regress_pg_dump_schema.test_func()        | role regress_dump_test_role  | i
+ function regress_pg_dump_schema.test_func()        | role regress_dump_test_super | i
+ function regress_pg_dump_schema.test_func()        | role regress_dump_test_super | o
+ function wgo_then_no_access()                      | role regress_dump_test_super | i
+ function wgo_then_no_access()                      | role regress_dump_test_super | o
+ schema regress_pg_dump_schema                      | role regress_dump_test_super | o
+ sequence regress_pg_dump_schema.test_seq           | role regress_dump_test_role  | a
+ sequence regress_pg_dump_schema.test_seq           | role regress_dump_test_role  | i
+ sequence regress_pg_dump_schema.test_seq           | role regress_dump_test_super | i
+ sequence regress_pg_dump_schema.test_seq           | role regress_dump_test_super | o
+ sequence regress_pg_dump_seq                       | role regress_dump_test_role  | a
+ sequence regress_pg_dump_seq                       | role regress_dump_test_role  | i
+ sequence regress_pg_dump_seq                       | role regress_dump_test_super | i
+ sequence regress_pg_dump_seq                       | role regress_dump_test_super | o
+ sequence regress_pg_dump_table_col1_seq            | role regress_dump_test_super | o
+ sequence regress_seq_dumpable                      | role regress_dump_test_super | i
+ sequence regress_seq_dumpable                      | role regress_dump_test_super | o
+ sequence wgo_then_regular                          | role regress_dump_test_super | i
+ sequence wgo_then_regular                          | role regress_dump_test_super | o
+ table regress_pg_dump_schema.test_table            | role regress_dump_test_role  | a
+ table regress_pg_dump_schema.test_table            | role regress_dump_test_role  | i
+ table regress_pg_dump_schema.test_table            | role regress_dump_test_super | i
+ table regress_pg_dump_schema.test_table            | role regress_dump_test_super | o
+ table regress_pg_dump_table                        | role regress_dump_test_role  | a
+ table regress_pg_dump_table                        | role regress_dump_test_role  | i
+ table regress_pg_dump_table                        | role regress_dump_test_super | i
+ table regress_pg_dump_table                        | role regress_dump_test_super | o
+ table regress_table_dumpable                       | role regress_dump_test_super | i
+ table regress_table_dumpable                       | role regress_dump_test_super | o
+ type regress_pg_dump_schema.test_type              | role regress_dump_test_role  | a
+ type regress_pg_dump_schema.test_type              | role regress_dump_test_role  | i
+ type regress_pg_dump_schema.test_type              | role regress_dump_test_super | i
+ type regress_pg_dump_schema.test_type              | role regress_dump_test_super | o
+(40 rows)
+
+REASSIGN OWNED BY regress_dump_test_super TO CURRENT_ROLE;
+-- Substitute for current user's name to keep test output consistent
+SELECT s.obj,
+  CASE WHEN a.grantor::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantor::regrole::name END,
+  CASE WHEN a.grantee::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantee::regrole::name END,
+  a.privilege_type, a.is_grantable
+FROM
+  (SELECT pg_describe_object(classoid,objoid,objsubid) COLLATE "C" AS obj, initprivs
+   FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1) s,
+  aclexplode(s.initprivs) a;
+                        obj                         | grantor  |        grantee         | privilege_type |
is_grantable 

+----------------------------------------------------+----------+------------------------+----------------+--------------
+ column col1 of table regress_pg_dump_table         | postgres | -                      | SELECT         | f
+ function regress_pg_dump_schema.test_agg(smallint) | postgres | -                      | EXECUTE        | f
+ function regress_pg_dump_schema.test_agg(smallint) | postgres | postgres               | EXECUTE        | f
+ function regress_pg_dump_schema.test_agg(smallint) | postgres | regress_dump_test_role | EXECUTE        | f
+ function regress_pg_dump_schema.test_func()        | postgres | -                      | EXECUTE        | f
+ function regress_pg_dump_schema.test_func()        | postgres | postgres               | EXECUTE        | f
+ function regress_pg_dump_schema.test_func()        | postgres | regress_dump_test_role | EXECUTE        | f
+ function wgo_then_no_access()                      | postgres | -                      | EXECUTE        | f
+ function wgo_then_no_access()                      | postgres | postgres               | EXECUTE        | f
+ function wgo_then_no_access()                      | postgres | pg_signal_backend      | EXECUTE        | t
+ sequence regress_pg_dump_schema.test_seq           | postgres | postgres               | SELECT         | f
+ sequence regress_pg_dump_schema.test_seq           | postgres | postgres               | UPDATE         | f
+ sequence regress_pg_dump_schema.test_seq           | postgres | postgres               | USAGE          | f
+ sequence regress_pg_dump_schema.test_seq           | postgres | regress_dump_test_role | USAGE          | f
+ sequence regress_pg_dump_seq                       | postgres | postgres               | SELECT         | f
+ sequence regress_pg_dump_seq                       | postgres | postgres               | UPDATE         | f
+ sequence regress_pg_dump_seq                       | postgres | postgres               | USAGE          | f
+ sequence regress_pg_dump_seq                       | postgres | regress_dump_test_role | USAGE          | f
+ sequence regress_seq_dumpable                      | postgres | postgres               | SELECT         | f
+ sequence regress_seq_dumpable                      | postgres | postgres               | UPDATE         | f
+ sequence regress_seq_dumpable                      | postgres | postgres               | USAGE          | f
+ sequence regress_seq_dumpable                      | postgres | -                      | SELECT         | f
+ sequence wgo_then_regular                          | postgres | postgres               | SELECT         | f
+ sequence wgo_then_regular                          | postgres | postgres               | UPDATE         | f
+ sequence wgo_then_regular                          | postgres | postgres               | USAGE          | f
+ sequence wgo_then_regular                          | postgres | pg_signal_backend      | SELECT         | f
+ sequence wgo_then_regular                          | postgres | pg_signal_backend      | UPDATE         | t
+ sequence wgo_then_regular                          | postgres | pg_signal_backend      | USAGE          | t
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | INSERT         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | SELECT         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | UPDATE         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | DELETE         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | TRUNCATE       | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | REFERENCES     | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | TRIGGER        | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres               | MAINTAIN       | f
+ table regress_pg_dump_schema.test_table            | postgres | regress_dump_test_role | SELECT         | f
+ table regress_pg_dump_table                        | postgres | postgres               | INSERT         | f
+ table regress_pg_dump_table                        | postgres | postgres               | SELECT         | f
+ table regress_pg_dump_table                        | postgres | postgres               | UPDATE         | f
+ table regress_pg_dump_table                        | postgres | postgres               | DELETE         | f
+ table regress_pg_dump_table                        | postgres | postgres               | TRUNCATE       | f
+ table regress_pg_dump_table                        | postgres | postgres               | REFERENCES     | f
+ table regress_pg_dump_table                        | postgres | postgres               | TRIGGER        | f
+ table regress_pg_dump_table                        | postgres | postgres               | MAINTAIN       | f
+ table regress_pg_dump_table                        | postgres | regress_dump_test_role | SELECT         | f
+ table regress_table_dumpable                       | postgres | postgres               | INSERT         | f
+ table regress_table_dumpable                       | postgres | postgres               | SELECT         | f
+ table regress_table_dumpable                       | postgres | postgres               | UPDATE         | f
+ table regress_table_dumpable                       | postgres | postgres               | DELETE         | f
+ table regress_table_dumpable                       | postgres | postgres               | TRUNCATE       | f
+ table regress_table_dumpable                       | postgres | postgres               | REFERENCES     | f
+ table regress_table_dumpable                       | postgres | postgres               | TRIGGER        | f
+ table regress_table_dumpable                       | postgres | postgres               | MAINTAIN       | f
+ table regress_table_dumpable                       | postgres | -                      | SELECT         | f
+ type regress_pg_dump_schema.test_type              | postgres | -                      | USAGE          | f
+ type regress_pg_dump_schema.test_type              | postgres | postgres               | USAGE          | f
+ type regress_pg_dump_schema.test_type              | postgres | regress_dump_test_role | USAGE          | f
+(58 rows)
+
+SELECT pg_describe_object(classid,objid,objsubid) COLLATE "C" AS obj,
+  pg_describe_object(refclassid,refobjid,0) AS refobj,
+  deptype
+  FROM pg_shdepend JOIN pg_database d ON dbid = d.oid
+  WHERE d.datname = current_database()
+  ORDER BY 1, 2, 3;
+                        obj                         |           refobj            | deptype
+----------------------------------------------------+-----------------------------+---------
+ function regress_pg_dump_schema.test_agg(smallint) | role regress_dump_test_role | a
+ function regress_pg_dump_schema.test_agg(smallint) | role regress_dump_test_role | i
+ function regress_pg_dump_schema.test_func()        | role regress_dump_test_role | a
+ function regress_pg_dump_schema.test_func()        | role regress_dump_test_role | i
+ sequence regress_pg_dump_schema.test_seq           | role regress_dump_test_role | a
+ sequence regress_pg_dump_schema.test_seq           | role regress_dump_test_role | i
+ sequence regress_pg_dump_seq                       | role regress_dump_test_role | a
+ sequence regress_pg_dump_seq                       | role regress_dump_test_role | i
+ table regress_pg_dump_schema.test_table            | role regress_dump_test_role | a
+ table regress_pg_dump_schema.test_table            | role regress_dump_test_role | i
+ table regress_pg_dump_table                        | role regress_dump_test_role | a
+ table regress_pg_dump_table                        | role regress_dump_test_role | i
+ type regress_pg_dump_schema.test_type              | role regress_dump_test_role | a
+ type regress_pg_dump_schema.test_type              | role regress_dump_test_role | i
+(14 rows)
+
+DROP OWNED BY regress_dump_test_role RESTRICT;
+-- Substitute for current user's name to keep test output consistent
+SELECT s.obj,
+  CASE WHEN a.grantor::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantor::regrole::name END,
+  CASE WHEN a.grantee::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantee::regrole::name END,
+  a.privilege_type, a.is_grantable
+FROM
+  (SELECT pg_describe_object(classoid,objoid,objsubid) COLLATE "C" AS obj, initprivs
+   FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1) s,
+  aclexplode(s.initprivs) a;
+                        obj                         | grantor  |      grantee      | privilege_type | is_grantable
+----------------------------------------------------+----------+-------------------+----------------+--------------
+ column col1 of table regress_pg_dump_table         | postgres | -                 | SELECT         | f
+ function regress_pg_dump_schema.test_agg(smallint) | postgres | -                 | EXECUTE        | f
+ function regress_pg_dump_schema.test_agg(smallint) | postgres | postgres          | EXECUTE        | f
+ function regress_pg_dump_schema.test_func()        | postgres | -                 | EXECUTE        | f
+ function regress_pg_dump_schema.test_func()        | postgres | postgres          | EXECUTE        | f
+ function wgo_then_no_access()                      | postgres | -                 | EXECUTE        | f
+ function wgo_then_no_access()                      | postgres | postgres          | EXECUTE        | f
+ function wgo_then_no_access()                      | postgres | pg_signal_backend | EXECUTE        | t
+ sequence regress_pg_dump_schema.test_seq           | postgres | postgres          | SELECT         | f
+ sequence regress_pg_dump_schema.test_seq           | postgres | postgres          | UPDATE         | f
+ sequence regress_pg_dump_schema.test_seq           | postgres | postgres          | USAGE          | f
+ sequence regress_pg_dump_seq                       | postgres | postgres          | SELECT         | f
+ sequence regress_pg_dump_seq                       | postgres | postgres          | UPDATE         | f
+ sequence regress_pg_dump_seq                       | postgres | postgres          | USAGE          | f
+ sequence regress_seq_dumpable                      | postgres | postgres          | SELECT         | f
+ sequence regress_seq_dumpable                      | postgres | postgres          | UPDATE         | f
+ sequence regress_seq_dumpable                      | postgres | postgres          | USAGE          | f
+ sequence regress_seq_dumpable                      | postgres | -                 | SELECT         | f
+ sequence wgo_then_regular                          | postgres | postgres          | SELECT         | f
+ sequence wgo_then_regular                          | postgres | postgres          | UPDATE         | f
+ sequence wgo_then_regular                          | postgres | postgres          | USAGE          | f
+ sequence wgo_then_regular                          | postgres | pg_signal_backend | SELECT         | f
+ sequence wgo_then_regular                          | postgres | pg_signal_backend | UPDATE         | t
+ sequence wgo_then_regular                          | postgres | pg_signal_backend | USAGE          | t
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | INSERT         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | SELECT         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | UPDATE         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | DELETE         | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | TRUNCATE       | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | REFERENCES     | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | TRIGGER        | f
+ table regress_pg_dump_schema.test_table            | postgres | postgres          | MAINTAIN       | f
+ table regress_pg_dump_table                        | postgres | postgres          | INSERT         | f
+ table regress_pg_dump_table                        | postgres | postgres          | SELECT         | f
+ table regress_pg_dump_table                        | postgres | postgres          | UPDATE         | f
+ table regress_pg_dump_table                        | postgres | postgres          | DELETE         | f
+ table regress_pg_dump_table                        | postgres | postgres          | TRUNCATE       | f
+ table regress_pg_dump_table                        | postgres | postgres          | REFERENCES     | f
+ table regress_pg_dump_table                        | postgres | postgres          | TRIGGER        | f
+ table regress_pg_dump_table                        | postgres | postgres          | MAINTAIN       | f
+ table regress_table_dumpable                       | postgres | postgres          | INSERT         | f
+ table regress_table_dumpable                       | postgres | postgres          | SELECT         | f
+ table regress_table_dumpable                       | postgres | postgres          | UPDATE         | f
+ table regress_table_dumpable                       | postgres | postgres          | DELETE         | f
+ table regress_table_dumpable                       | postgres | postgres          | TRUNCATE       | f
+ table regress_table_dumpable                       | postgres | postgres          | REFERENCES     | f
+ table regress_table_dumpable                       | postgres | postgres          | TRIGGER        | f
+ table regress_table_dumpable                       | postgres | postgres          | MAINTAIN       | f
+ table regress_table_dumpable                       | postgres | -                 | SELECT         | f
+ type regress_pg_dump_schema.test_type              | postgres | -                 | USAGE          | f
+ type regress_pg_dump_schema.test_type              | postgres | postgres          | USAGE          | f
+(51 rows)
+
+SELECT pg_describe_object(classid,objid,objsubid) COLLATE "C" AS obj,
+  pg_describe_object(refclassid,refobjid,0) AS refobj,
+  deptype
+  FROM pg_shdepend JOIN pg_database d ON dbid = d.oid
+  WHERE d.datname = current_database()
+  ORDER BY 1, 2, 3;
+ obj | refobj | deptype
+-----+--------+---------
+(0 rows)
+
+DROP ROLE regress_dump_test_super;
+DROP ROLE regress_dump_test_role;
diff --git a/src/test/modules/test_pg_dump/sql/test_pg_dump.sql b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql
index 2110ac7163..87e66cae6e 100644
--- a/src/test/modules/test_pg_dump/sql/test_pg_dump.sql
+++ b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql
@@ -151,3 +151,74 @@ DROP EXTENSION test_pg_dump;

 -- shouldn't be anything left in pg_init_privs
 SELECT * FROM pg_init_privs WHERE privtype = 'e';
+
+CREATE ROLE regress_dump_test_role;
+CREATE ROLE regress_dump_test_super SUPERUSER;
+
+SET ROLE regress_dump_test_super;
+
+CREATE EXTENSION test_pg_dump;
+
+RESET ROLE;
+
+-- Substitute for current user's name to keep test output consistent
+SELECT s.obj,
+  CASE WHEN a.grantor::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantor::regrole::name END,
+  CASE WHEN a.grantee::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantee::regrole::name END,
+  a.privilege_type, a.is_grantable
+FROM
+  (SELECT pg_describe_object(classoid,objoid,objsubid) COLLATE "C" AS obj, initprivs
+   FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1) s,
+  aclexplode(s.initprivs) a;
+SELECT pg_describe_object(classid,objid,objsubid) COLLATE "C" AS obj,
+  pg_describe_object(refclassid,refobjid,0) AS refobj,
+  deptype
+  FROM pg_shdepend JOIN pg_database d ON dbid = d.oid
+  WHERE d.datname = current_database()
+  ORDER BY 1, 2, 3;
+
+REASSIGN OWNED BY regress_dump_test_super TO CURRENT_ROLE;
+
+-- Substitute for current user's name to keep test output consistent
+SELECT s.obj,
+  CASE WHEN a.grantor::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantor::regrole::name END,
+  CASE WHEN a.grantee::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantee::regrole::name END,
+  a.privilege_type, a.is_grantable
+FROM
+  (SELECT pg_describe_object(classoid,objoid,objsubid) COLLATE "C" AS obj, initprivs
+   FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1) s,
+  aclexplode(s.initprivs) a;
+SELECT pg_describe_object(classid,objid,objsubid) COLLATE "C" AS obj,
+  pg_describe_object(refclassid,refobjid,0) AS refobj,
+  deptype
+  FROM pg_shdepend JOIN pg_database d ON dbid = d.oid
+  WHERE d.datname = current_database()
+  ORDER BY 1, 2, 3;
+
+DROP OWNED BY regress_dump_test_role RESTRICT;
+
+-- Substitute for current user's name to keep test output consistent
+SELECT s.obj,
+  CASE WHEN a.grantor::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantor::regrole::name END,
+  CASE WHEN a.grantee::regrole::name = quote_ident(current_user) THEN 'postgres'
+    ELSE a.grantee::regrole::name END,
+  a.privilege_type, a.is_grantable
+FROM
+  (SELECT pg_describe_object(classoid,objoid,objsubid) COLLATE "C" AS obj, initprivs
+   FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1) s,
+  aclexplode(s.initprivs) a;
+SELECT pg_describe_object(classid,objid,objsubid) COLLATE "C" AS obj,
+  pg_describe_object(refclassid,refobjid,0) AS refobj,
+  deptype
+  FROM pg_shdepend JOIN pg_database d ON dbid = d.oid
+  WHERE d.datname = current_database()
+  ORDER BY 1, 2, 3;
+
+DROP ROLE regress_dump_test_super;
+
+DROP ROLE regress_dump_test_role;

pgsql-hackers by date:

Previous
From: Thomas Munro
Date:
Subject: Re: Using LibPq in TAP tests via FFI
Next
From: Jeff Davis
Date:
Subject: Speed up collation cache