I wrote:
> Here's a draft patch that attacks that.  It seems to fix the
> problem with test_pg_dump: no dangling pg_init_privs grants
> are left behind.

Here's a v2 that attempts to add some queries to test_pg_dump.sql
to provide visual verification that pg_shdepend and pg_init_privs
are updated correctly during DROP OWNED BY.  It's a little bit
nasty to look at the ACL column of pg_init_privs, because that text
involves the bootstrap superuser's name which is site-dependent.
What I did to try to make the test stable is

  replace(initprivs::text, current_user, 'postgres') AS initprivs

This is of course not bulletproof: with a sufficiently weird
bootstrap superuser name, we could get false matches to parts
of "regress_dump_test_role" or to privilege strings.  That
seems unlikely enough to live with, but I wonder if anybody has
a better idea.

                        regards, tom lane

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 2907079e2a..c8cb46c5b9 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7184,6 +7184,20 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><symbol>SHARED_DEPENDENCY_INITACL</symbol> (<literal>i</literal>)</term>
+     <listitem>
+      <para>
+       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>
+
     <varlistentry>
      <term><symbol>SHARED_DEPENDENCY_POLICY</symbol> (<literal>r</literal>)</term>
      <listitem>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 7abf3c2a74..04c41c0c14 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -165,9 +165,9 @@ static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
 								   AclMode mask, AclMaskHow how,
 								   bool *is_missing);
 static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
-									Acl *new_acl);
+									Oid ownerId, Acl *new_acl);
 static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
-										  Acl *new_acl);
+										  Oid ownerId, Acl *new_acl);
 
 
 /*
@@ -1790,7 +1790,7 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
 		CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
 
 		/* Update initial privileges for extensions */
-		recordExtensionInitPriv(relOid, RelationRelationId, attnum,
+		recordExtensionInitPriv(relOid, RelationRelationId, attnum, ownerId,
 								ACL_NUM(new_acl) > 0 ? new_acl : NULL);
 
 		/* Update the shared dependency ACL info */
@@ -2050,7 +2050,8 @@ ExecGrant_Relation(InternalGrant *istmt)
 			CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
 
 			/* Update initial privileges for extensions */
-			recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
+			recordExtensionInitPriv(relOid, RelationRelationId, 0,
+									ownerId, new_acl);
 
 			/* Update the shared dependency ACL info */
 			updateAclDependencies(RelationRelationId, relOid, 0,
@@ -2251,7 +2252,7 @@ ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
 
 		/* Update initial privileges for extensions */
-		recordExtensionInitPriv(objectid, classid, 0, new_acl);
+		recordExtensionInitPriv(objectid, classid, 0, ownerId, new_acl);
 
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(classid,
@@ -2403,7 +2404,8 @@ ExecGrant_Largeobject(InternalGrant *istmt)
 		CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
 
 		/* Update initial privileges for extensions */
-		recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
+		recordExtensionInitPriv(loid, LargeObjectRelationId, 0,
+								ownerId, new_acl);
 
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(LargeObjectRelationId,
@@ -2575,7 +2577,7 @@ ExecGrant_Parameter(InternalGrant *istmt)
 
 		/* Update initial privileges for extensions */
 		recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
-								new_acl);
+								ownerId, new_acl);
 
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ParameterAclRelationId, parameterId, 0,
@@ -4463,6 +4465,7 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 				}
 
 				recordExtensionInitPrivWorker(objoid, classoid, curr_att,
+											  pg_class_tuple->relowner,
 											  DatumGetAclP(attaclDatum));
 
 				ReleaseSysCache(attTuple);
@@ -4475,6 +4478,7 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 		/* Add the record, if any, for the top-level object */
 		if (!isNull)
 			recordExtensionInitPrivWorker(objoid, classoid, 0,
+										  pg_class_tuple->relowner,
 										  DatumGetAclP(aclDatum));
 
 		ReleaseSysCache(tuple);
@@ -4485,6 +4489,7 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 		Datum		aclDatum;
 		bool		isNull;
 		HeapTuple	tuple;
+		Form_pg_largeobject_metadata form_lo_meta;
 		ScanKeyData entry[1];
 		SysScanDesc scan;
 		Relation	relation;
@@ -4509,6 +4514,7 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 		tuple = systable_getnext(scan);
 		if (!HeapTupleIsValid(tuple))
 			elog(ERROR, "could not find tuple for large object %u", objoid);
+		form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
 
 		aclDatum = heap_getattr(tuple,
 								Anum_pg_largeobject_metadata_lomacl,
@@ -4517,6 +4523,7 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 		/* Add the record, if any, for the top-level object */
 		if (!isNull)
 			recordExtensionInitPrivWorker(objoid, classoid, 0,
+										  form_lo_meta->lomowner,
 										  DatumGetAclP(aclDatum));
 
 		systable_endscan(scan);
@@ -4524,24 +4531,29 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 	/* This will error on unsupported classoid. */
 	else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
 	{
+		int			cacheid;
+		Oid			ownerId;
 		Datum		aclDatum;
 		bool		isNull;
 		HeapTuple	tuple;
 
-		tuple = SearchSysCache1(get_object_catcache_oid(classoid),
-								ObjectIdGetDatum(objoid));
+		cacheid = get_object_catcache_oid(classoid);
+		tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
 		if (!HeapTupleIsValid(tuple))
 			elog(ERROR, "cache lookup failed for %s %u",
 				 get_object_class_descr(classoid), objoid);
 
-		aclDatum = SysCacheGetAttr(get_object_catcache_oid(classoid), tuple,
+		ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
+														  tuple,
+														  get_object_attnum_owner(classoid)));
+		aclDatum = SysCacheGetAttr(cacheid, tuple,
 								   get_object_attnum_acl(classoid),
 								   &isNull);
 
 		/* Add the record, if any, for the top-level object */
 		if (!isNull)
 			recordExtensionInitPrivWorker(objoid, classoid, 0,
-										  DatumGetAclP(aclDatum));
+										  ownerId, DatumGetAclP(aclDatum));
 
 		ReleaseSysCache(tuple);
 	}
@@ -4554,6 +4566,8 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 void
 removeExtObjInitPriv(Oid objoid, Oid classoid)
 {
+	Oid			ownerId;
+
 	/*
 	 * If this is a relation then we need to see if there are any sub-objects
 	 * (eg: columns) for it and, if so, be sure to call
@@ -4568,6 +4582,7 @@ removeExtObjInitPriv(Oid objoid, Oid classoid)
 		if (!HeapTupleIsValid(tuple))
 			elog(ERROR, "cache lookup failed for relation %u", objoid);
 		pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
+		ownerId = pg_class_tuple->relowner;
 
 		/*
 		 * Indexes don't have permissions, neither do the pg_class rows for
@@ -4604,7 +4619,8 @@ removeExtObjInitPriv(Oid objoid, Oid classoid)
 
 				/* when removing, remove all entries, even dropped columns */
 
-				recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
+				recordExtensionInitPrivWorker(objoid, classoid, curr_att,
+											  ownerId, NULL);
 
 				ReleaseSysCache(attTuple);
 			}
@@ -4612,9 +4628,35 @@ removeExtObjInitPriv(Oid objoid, Oid classoid)
 
 		ReleaseSysCache(tuple);
 	}
+	else
+	{
+		/* Must find out the owner's OID the hard way */
+		AttrNumber	ownerattnum;
+		int			cacheid;
+		HeapTuple	tuple;
+
+		/*
+		 * If the object is of a type that has no owner, it should not have
+		 * any pg_init_privs entry either.
+		 */
+		ownerattnum = get_object_attnum_owner(classoid);
+		if (ownerattnum == InvalidAttrNumber)
+			return;
+		cacheid = get_object_catcache_oid(classoid);
+		tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
+		if (!HeapTupleIsValid(tuple))
+			elog(ERROR, "cache lookup failed for %s %u",
+				 get_object_class_descr(classoid), objoid);
+
+		ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
+														  tuple,
+														  ownerattnum));
+
+		ReleaseSysCache(tuple);
+	}
 
 	/* Remove the record, if any, for the top-level object */
-	recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
+	recordExtensionInitPrivWorker(objoid, classoid, 0, ownerId, NULL);
 }
 
 /*
@@ -4626,7 +4668,8 @@ removeExtObjInitPriv(Oid objoid, Oid classoid)
  * Pass in the object OID, the OID of the class (the OID of the table which
  * the object is defined in) and the 'sub' id of the object (objsubid), if
  * any.  If there is no 'sub' id (they are currently only used for columns of
- * tables) then pass in '0'.  Finally, pass in the complete ACL to store.
+ * tables) then pass in '0'.  Also pass the OID of the object's owner.
+ * Finally, pass in the complete ACL to store.
  *
  * If an ACL already exists for this object/sub-object then we will replace
  * it with what is passed in.
@@ -4635,7 +4678,8 @@ removeExtObjInitPriv(Oid objoid, Oid classoid)
  * removed, if one is found.
  */
 static void
-recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
+recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
+						Oid ownerId, Acl *new_acl)
 {
 	/*
 	 * Generally, we only record the initial privileges when an extension is
@@ -4648,7 +4692,7 @@ recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
 	if (!creating_extension && !binary_upgrade_record_init_privs)
 		return;
 
-	recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
+	recordExtensionInitPrivWorker(objoid, classoid, objsubid, ownerId, new_acl);
 }
 
 /*
@@ -4664,14 +4708,23 @@ recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
  * EXTENSION ... ADD/DROP.
  */
 static void
-recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
+recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
+							  Oid ownerId, Acl *new_acl)
 {
 	Relation	relation;
 	ScanKeyData key[3];
 	SysScanDesc scan;
 	HeapTuple	tuple;
 	HeapTuple	oldtuple;
+	int			noldmembers;
+	int			nnewmembers;
+	Oid		   *oldmembers;
+	Oid		   *newmembers;
 
+	/* We'll need the role membership of the new ACL. */
+	nnewmembers = aclmembers(new_acl, &newmembers);
+
+	/* Search pg_init_privs for an existing entry. */
 	relation = table_open(InitPrivsRelationId, RowExclusiveLock);
 
 	ScanKeyInit(&key[0],
@@ -4699,6 +4752,23 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_a
 		Datum		values[Natts_pg_init_privs] = {0};
 		bool		nulls[Natts_pg_init_privs] = {0};
 		bool		replace[Natts_pg_init_privs] = {0};
+		Datum		oldAclDatum;
+		bool		isNull;
+		Acl		   *old_acl;
+
+		/* Update pg_shdepend for roles mentioned in the old/new ACLs. */
+		oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
+								   RelationGetDescr(relation), &isNull);
+		if (!isNull)
+			old_acl = DatumGetAclP(oldAclDatum);
+		else
+			old_acl = NULL;		/* this case shouldn't happen, probably */
+		noldmembers = aclmembers(old_acl, &oldmembers);
+
+		updateInitAclDependencies(classoid, objoid, objsubid,
+								  ownerId,
+								  noldmembers, oldmembers,
+								  nnewmembers, newmembers);
 
 		/* If we have a new ACL to set, then update the row with it. */
 		if (new_acl)
@@ -4744,6 +4814,15 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_a
 			tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
 
 			CatalogTupleInsert(relation, tuple);
+
+			/* Update pg_shdepend, too. */
+			noldmembers = 0;
+			oldmembers = NULL;
+
+			updateInitAclDependencies(classoid, objoid, objsubid,
+									  ownerId,
+									  noldmembers, oldmembers,
+									  nnewmembers, newmembers);
 		}
 	}
 
@@ -4754,3 +4833,138 @@ recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_a
 
 	table_close(relation, RowExclusiveLock);
 }
+
+/*
+ * RemoveRoleFromInitPriv
+ *
+ * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
+ */
+void
+RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
+{
+	Relation	rel;
+	ScanKeyData key[3];
+	SysScanDesc scan;
+	HeapTuple	oldtuple;
+	int			cacheid;
+	HeapTuple	objtuple;
+	Oid			ownerId;
+	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)
+		old_acl = DatumGetAclPCopy(oldAclDatum);
+	else
+		old_acl = NULL;			/* this case shouldn't happen, probably */
+
+	/*
+	 * We need the members of both old and new ACLs so we can correct the
+	 * shared dependency information.  Collect data before
+	 * merge_acl_with_grant throws away old_acl.
+	 */
+	noldmembers = aclmembers(old_acl, &oldmembers);
+
+	/* Must find out the owner's OID the hard way. */
+	cacheid = get_object_catcache_oid(classid);
+	objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
+	if (!HeapTupleIsValid(objtuple))
+		elog(ERROR, "cache lookup failed for %s %u",
+			 get_object_class_descr(classid), objid);
+
+	ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
+													  objtuple,
+													  get_object_attnum_owner(classid)));
+	ReleaseSysCache(objtuple);
+
+	/*
+	 * Generate new ACL.  Grantor of rights is always the same as the owner.
+	 */
+	new_acl = merge_acl_with_grant(old_acl,
+								   false,	/* is_grant */
+								   false,	/* grant_option */
+								   DROP_RESTRICT,
+								   list_make1_oid(roleid),
+								   ACLITEM_ALL_PRIV_BITS,
+								   ownerId,
+								   ownerId);
+
+	/* If we end with an empty ACL, delete the pg_init_privs entry. */
+	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.
+	 */
+	nnewmembers = aclmembers(new_acl, &newmembers);
+
+	updateInitAclDependencies(classid, objid, objsubid,
+							  ownerId,
+							  noldmembers, oldmembers,
+							  nnewmembers, newmembers);
+
+	systable_endscan(scan);
+
+	/* prevent error when processing objects multiple times */
+	CommandCounterIncrement();
+
+	table_close(rel, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index cb31590339..20bcfd779b 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -84,6 +84,11 @@ static void shdepChangeDep(Relation sdepRel,
 						   Oid classid, Oid objid, int32 objsubid,
 						   Oid refclassid, Oid refobjid,
 						   SharedDependencyType deptype);
+static void updateAclDependenciesWorker(Oid classId, Oid objectId,
+										int32 objsubId, Oid ownerId,
+										SharedDependencyType deptype,
+										int noldmembers, Oid *oldmembers,
+										int nnewmembers, Oid *newmembers);
 static void shdepAddDependency(Relation sdepRel,
 							   Oid classId, Oid objectId, int32 objsubId,
 							   Oid refclassId, Oid refobjId,
@@ -340,6 +345,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);
+
 	table_close(sdepRel, RowExclusiveLock);
 }
 
@@ -478,6 +488,38 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
 					  Oid ownerId,
 					  int noldmembers, Oid *oldmembers,
 					  int nnewmembers, Oid *newmembers)
+{
+	updateAclDependenciesWorker(classId, objectId, objsubId,
+								ownerId, SHARED_DEPENDENCY_ACL,
+								noldmembers, oldmembers,
+								nnewmembers, newmembers);
+}
+
+/*
+ * updateInitAclDependencies
+ *		Update the pg_shdepend info for a pg_init_privs entry.
+ *
+ * Exactly like updateAclDependencies, except we are considering a
+ * pg_init_privs ACL for the specified object.
+ */
+void
+updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId,
+						  Oid ownerId,
+						  int noldmembers, Oid *oldmembers,
+						  int nnewmembers, Oid *newmembers)
+{
+	updateAclDependenciesWorker(classId, objectId, objsubId,
+								ownerId, SHARED_DEPENDENCY_INITACL,
+								noldmembers, oldmembers,
+								nnewmembers, newmembers);
+}
+
+/* Common code for the above two functions */
+static void
+updateAclDependenciesWorker(Oid classId, Oid objectId, int32 objsubId,
+							Oid ownerId, SharedDependencyType deptype,
+							int noldmembers, Oid *oldmembers,
+							int nnewmembers, Oid *newmembers)
 {
 	Relation	sdepRel;
 	int			i;
@@ -513,7 +555,7 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
 
 			shdepAddDependency(sdepRel, classId, objectId, objsubId,
 							   AuthIdRelationId, roleid,
-							   SHARED_DEPENDENCY_ACL);
+							   deptype);
 		}
 
 		/* Drop no-longer-used old dependencies */
@@ -532,7 +574,7 @@ updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
 			shdepDropDependency(sdepRel, classId, objectId, objsubId,
 								false,	/* exact match on objsubId */
 								AuthIdRelationId, roleid,
-								SHARED_DEPENDENCY_ACL);
+								deptype);
 		}
 
 		table_close(sdepRel, RowExclusiveLock);
@@ -1249,6 +1291,8 @@ storeObjectDescription(StringInfo descs,
 				appendStringInfo(descs, _("owner of %s"), objdesc);
 			else if (deptype == SHARED_DEPENDENCY_ACL)
 				appendStringInfo(descs, _("privileges for %s"), objdesc);
+			else if (deptype == SHARED_DEPENDENCY_INITACL)
+				appendStringInfo(descs, _("initial privileges for %s"), objdesc);
 			else if (deptype == SHARED_DEPENDENCY_POLICY)
 				appendStringInfo(descs, _("target of %s"), objdesc);
 			else if (deptype == SHARED_DEPENDENCY_TABLESPACE)
@@ -1431,6 +1475,14 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
 						add_exact_object_address(&obj, deleteobjs);
 					}
 					break;
+				case SHARED_DEPENDENCY_INITACL:
+					/* Shouldn't see a role grant here */
+					Assert(sdepForm->classid != AuthMemRelationId);
+					RemoveRoleFromInitPriv(roleid,
+										   sdepForm->classid,
+										   sdepForm->objid,
+										   sdepForm->objsubid);
+					break;
 			}
 		}
 
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index ec654010d4..e0dcc0b069 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -56,11 +56,17 @@ typedef enum DependencyType
  * 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.)
  *
- * (c) a SHARED_DEPENDENCY_POLICY entry means that the referenced object is
+ * (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.)
+ *
+ * (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
  * pg_authid entry.
  *
- * (d) a SHARED_DEPENDENCY_TABLESPACE entry means that the referenced
+ * (e) a SHARED_DEPENDENCY_TABLESPACE entry means that the referenced
  * object is a tablespace mentioned in a relation without storage.  The
  * referenced object must be a pg_tablespace entry.  (Relations that have
  * storage don't need this: they are protected by the existence of a physical
@@ -73,6 +79,7 @@ typedef enum SharedDependencyType
 {
 	SHARED_DEPENDENCY_OWNER = 'o',
 	SHARED_DEPENDENCY_ACL = 'a',
+	SHARED_DEPENDENCY_INITACL = 'i',
 	SHARED_DEPENDENCY_POLICY = 'r',
 	SHARED_DEPENDENCY_TABLESPACE = 't',
 	SHARED_DEPENDENCY_INVALID = 0,
@@ -201,6 +208,11 @@ extern void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
 								  int noldmembers, Oid *oldmembers,
 								  int nnewmembers, Oid *newmembers);
 
+extern void updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId,
+									  Oid ownerId,
+									  int noldmembers, Oid *oldmembers,
+									  int nnewmembers, Oid *newmembers);
+
 extern bool checkSharedDependencies(Oid classId, Oid objectId,
 									char **detail_msg, char **detail_log_msg);
 
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 3a0baf3039..1a554c6699 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 RemoveRoleFromInitPriv(Oid roleid,
+								   Oid classid, Oid objid, int32 objsubid);
 
 
 /* ownercheck routines just return true (owner) or false (not) */
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 f57c96aeb9..be71822ece 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
@@ -62,6 +62,59 @@ GRANT SELECT ON ft1 TO regress_dump_test_role;
 GRANT UPDATE ON test_pg_dump_mv1 TO regress_dump_test_role;
 GRANT USAGE ON SCHEMA test_pg_dump_s1 TO regress_dump_test_role;
 GRANT USAGE ON TYPE test_pg_dump_e1 TO regress_dump_test_role;
+SELECT pg_describe_object(classoid,objoid,objsubid) AS obj,
+  replace(initprivs::text, current_user, 'postgres') AS initprivs
+  FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1;
+                        obj                         |                              initprivs                              
+----------------------------------------------------+---------------------------------------------------------------------
+ column col1 of table regress_pg_dump_table         | {=r/postgres}
+ function regress_pg_dump_schema.test_agg(smallint) | {=X/postgres,postgres=X/postgres,regress_dump_test_role=X/postgres}
+ function regress_pg_dump_schema.test_func()        | {=X/postgres,postgres=X/postgres,regress_dump_test_role=X/postgres}
+ function wgo_then_no_access()                      | {=X/postgres,postgres=X/postgres,pg_signal_backend=X*/postgres}
+ sequence regress_pg_dump_schema.test_seq           | {postgres=rwU/postgres,regress_dump_test_role=U/postgres}
+ sequence regress_pg_dump_seq                       | {postgres=rwU/postgres,regress_dump_test_role=U/postgres}
+ sequence regress_seq_dumpable                      | {postgres=rwU/postgres,=r/postgres}
+ sequence wgo_then_regular                          | {postgres=rwU/postgres,pg_signal_backend=rw*U*/postgres}
+ table regress_pg_dump_schema.test_table            | {postgres=arwdDxtm/postgres,regress_dump_test_role=r/postgres}
+ table regress_pg_dump_table                        | {postgres=arwdDxtm/postgres,regress_dump_test_role=r/postgres}
+ table regress_table_dumpable                       | {postgres=arwdDxtm/postgres,=r/postgres}
+ type regress_pg_dump_schema.test_type              | {=U/postgres,postgres=U/postgres,regress_dump_test_role=U/postgres}
+(12 rows)
+
+SELECT pg_describe_object(classid,objid,objsubid) 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, 3;
+                        obj                         |           refobj            | deptype 
+----------------------------------------------------+-----------------------------+---------
+ column c1 of foreign table ft1                     | role regress_dump_test_role | a
+ column c1 of table test_pg_dump_t1                 | role regress_dump_test_role | a
+ foreign table ft1                                  | role regress_dump_test_role | a
+ foreign-data wrapper dummy                         | role regress_dump_test_role | a
+ 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
+ function test_pg_dump(integer)                     | role regress_dump_test_role | a
+ materialized view test_pg_dump_mv1                 | role regress_dump_test_role | a
+ schema test_pg_dump_s1                             | role regress_dump_test_role | a
+ 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
+ server s0                                          | role regress_dump_test_role | a
+ 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
+ type test_pg_dump_e1                               | role regress_dump_test_role | a
+ view test_pg_dump_v1                               | role regress_dump_test_role | a
+(24 rows)
+
 ALTER EXTENSION test_pg_dump ADD ACCESS METHOD gist2;
 ALTER EXTENSION test_pg_dump ADD AGGREGATE newavg(int4);
 ALTER EXTENSION test_pg_dump ADD CAST (text AS casttesttype);
@@ -92,4 +145,33 @@ ALTER EXTENSION test_pg_dump DROP TABLE test_pg_dump_t1;
 ALTER EXTENSION test_pg_dump DROP TYPE test_pg_dump_e1;
 ALTER EXTENSION test_pg_dump DROP VIEW test_pg_dump_v1;
 DROP OWNED BY regress_dump_test_role RESTRICT;
+SELECT pg_describe_object(classoid,objoid,objsubid) AS obj,
+  replace(initprivs::text, current_user, 'postgres') AS initprivs
+  FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1;
+                        obj                         |                            initprivs                            
+----------------------------------------------------+-----------------------------------------------------------------
+ column col1 of table regress_pg_dump_table         | {=r/postgres}
+ function regress_pg_dump_schema.test_agg(smallint) | {=X/postgres,postgres=X/postgres}
+ function regress_pg_dump_schema.test_func()        | {=X/postgres,postgres=X/postgres}
+ function wgo_then_no_access()                      | {=X/postgres,postgres=X/postgres,pg_signal_backend=X*/postgres}
+ sequence regress_pg_dump_schema.test_seq           | {postgres=rwU/postgres}
+ sequence regress_pg_dump_seq                       | {postgres=rwU/postgres}
+ sequence regress_seq_dumpable                      | {postgres=rwU/postgres,=r/postgres}
+ sequence wgo_then_regular                          | {postgres=rwU/postgres,pg_signal_backend=rw*U*/postgres}
+ table regress_pg_dump_schema.test_table            | {postgres=arwdDxtm/postgres}
+ table regress_pg_dump_table                        | {postgres=arwdDxtm/postgres}
+ table regress_table_dumpable                       | {postgres=arwdDxtm/postgres,=r/postgres}
+ type regress_pg_dump_schema.test_type              | {=U/postgres,postgres=U/postgres}
+(12 rows)
+
+SELECT pg_describe_object(classid,objid,objsubid) 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, 3;
+ obj | refobj | deptype 
+-----+--------+---------
+(0 rows)
+
 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 4f1eb9d429..0d48256883 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
@@ -75,6 +75,16 @@ GRANT UPDATE ON test_pg_dump_mv1 TO regress_dump_test_role;
 GRANT USAGE ON SCHEMA test_pg_dump_s1 TO regress_dump_test_role;
 GRANT USAGE ON TYPE test_pg_dump_e1 TO regress_dump_test_role;
 
+SELECT pg_describe_object(classoid,objoid,objsubid) AS obj,
+  replace(initprivs::text, current_user, 'postgres') AS initprivs
+  FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1;
+SELECT pg_describe_object(classid,objid,objsubid) 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, 3;
+
 ALTER EXTENSION test_pg_dump ADD ACCESS METHOD gist2;
 ALTER EXTENSION test_pg_dump ADD AGGREGATE newavg(int4);
 ALTER EXTENSION test_pg_dump ADD CAST (text AS casttesttype);
@@ -108,4 +118,15 @@ ALTER EXTENSION test_pg_dump DROP TYPE test_pg_dump_e1;
 ALTER EXTENSION test_pg_dump DROP VIEW test_pg_dump_v1;
 
 DROP OWNED BY regress_dump_test_role RESTRICT;
+
+SELECT pg_describe_object(classoid,objoid,objsubid) AS obj,
+  replace(initprivs::text, current_user, 'postgres') AS initprivs
+  FROM pg_init_privs WHERE privtype = 'e' ORDER BY 1;
+SELECT pg_describe_object(classid,objid,objsubid) 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, 3;
+
 DROP ROLE regress_dump_test_role;

Reply via email to