Re: pg_dump dump catalog ACLs

Started by Stephen Frostalmost 10 years ago35 messages
#1Stephen Frost
sfrost@snowman.net
1 attachment(s)

Tom, all,

* Tom Lane (tgl@sss.pgh.pa.us) wrote:

Joe Conway <mail@joeconway.com> writes:

Would it be a terrible idea to add some attribute to ACLs which can be
used to indicate they should not be dumped (and supporting syntax)?

Yes, we'd need some way to mark non-null ACLs as being "built-in
defaults". I do not see the need to have SQL syntax supporting that
though.

The attached patch does this by adding a 'pg_init_privs' catalog and
populating that catalog at the end of initdb, after all of the initial
privileges have been set up.

Actually, wouldn't you need to mark individual aclitems as built-in
or not? Consider a situation where we have some function foo() that
by default has EXECUTE permission granted to some built-in "pg_admin"
role. If a given installation then also grants EXECUTE to "joe",
what you really want to have happen is for pg_dump to dump only the
grant to "joe". Mentioning pg_admin's grant would tie the dump to
a particular major PG version's idea of what the built-in roles are,
which is what I'm arguing we need to avoid.

What I was thinking about for this was to have pg_dump simply not dump
out any GRANTs made to default roles (those starting with 'pg_'), as
part of the default roles patch.

Another option would be to have pg_dump figure out the delta between
what the initial privileges were, as recorded in pg_init_privs, as what
the current rights are.

I was thinking that the former was simpler, but I don't think it'd be
too difficult to do the latter if the consensus is that it's better to
do so.

I guess this could also be addressed by having two separate aclitem[]
columns, one that is expected to be frozen after initdb and one for
user-added grants.

This is along the lines of what I've done, but I've used a new catalog
instead, which is quite small and doesn't complicate or change the
regular catalogs.

* Joe Conway (mail@joeconway.com) wrote:

On 03/02/2016 12:54 PM, Stephen Frost wrote:

* Joe Conway (mail@joeconway.com) wrote:

On 03/01/2016 08:00 AM, Tom Lane wrote:

Yes, we'd need some way to mark non-null ACLs as being "built-in
defaults". I do not see the need to have SQL syntax supporting that
though.

I was thinking the supporting syntax might be used by extensions, for
example.

I tend to agree with Tom that we don't really need SQL syntax for this.

I don't see any reason it couldn't be used by extensions also, though
we'd have to do a bit more work on pg_dump to make it actually dump
out any non-default ACLs for extension-owned objects.

Without any syntax, what does the extension do, directly insert into
this special catalog table?

I've not included it in this patch, but my thinking here would be to add
a check to the GRANT functions which checks 'if (creating_extension)'
and records/updates the entries in pg_init_privs for those objects.
This is similar to how we handle dependencies for extensions currently.
That way, extensions don't have to do anything and if the user changes
the permissions on an extension's object, the permissions for that
object would then be dumped out.

This still requires more testing, documentation, and I'll see about
making it work completely for extensions also, but wanted to provide an
update and solicit for review/comments.

The patches have been broken up in what I hope is a logical way for
those who wish to review/comment:

#1 - Add the pg_init_privs catalog
#2 - Change pg_dump to use a bitmap instead of boolean for 'dump'
#3 - Split 'dump' into 'dump' and 'dump_contains'
#4 - Make pg_dump include changed ACLs in dump of 'pg_catalog'
#5 - Remove 'if (!superuser()) ereport()' calls and REVOKE EXECUTE

Thanks!

Stephen

Attachments:

catalog_acls_v3.patchtext/x-diff; charset=us-asciiDownload
From 31f4fafeaa06ad7c72ee7c6699253a65ea542d11 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Thu, 10 Mar 2016 20:56:09 -0500
Subject: [PATCH 1/5] Add new catalog called pg_init_privs

This new catalog will hold the privileges which the system is
initialized with at initdb time.  This will allow pg_dump
(and any other similar use-cases) to detect when the privileges
set on objects in pg_catalog have been changed and handle those
changes appropriately.

This could be extended to work for extensions also, but that
seems like an independent enough change that it should be in a
different commit.
---
 src/backend/catalog/Makefile               |   2 +-
 src/bin/initdb/initdb.c                    | 121 +++++++++++++++++++++++++++++
 src/include/catalog/indexing.h             |   3 +
 src/include/catalog/pg_init_privs.h        |  83 ++++++++++++++++++++
 src/test/regress/expected/sanity_check.out |   1 +
 5 files changed, 209 insertions(+), 1 deletion(-)
 create mode 100644 src/include/catalog/pg_init_privs.h

diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 25130ec..1ce7610 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -40,7 +40,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_ts_parser.h pg_ts_template.h pg_extension.h \
 	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
 	pg_foreign_table.h pg_policy.h pg_replication_origin.h \
-	pg_default_acl.h pg_seclabel.h pg_shseclabel.h \
+	pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
 	pg_collation.h pg_range.h pg_transform.h \
 	toasting.h indexing.h \
     )
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index ed3ba7b..b0c7234 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1989,6 +1989,11 @@ setup_dictionary(FILE *cmdfd)
  * Some objects may require different permissions by default, so we
  * make sure we don't overwrite privilege sets that have already been
  * set (NOT NULL).
+ *
+ * Also populate pg_init_privs to save what the privileges are at init
+ * time.  This is used by pg_dump to allow users to change privileges
+ * on catalog objects and to have those privilege changes preserved
+ * across dump/reload and pg_upgrade.
  */
 static void
 setup_privileges(FILE *cmdfd)
@@ -2002,6 +2007,122 @@ setup_privileges(FILE *cmdfd)
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
 		"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        0,"
+		"        relacl"
+		"    FROM"
+		"        pg_class"
+		"    WHERE"
+		"        relacl IS NOT NULL"
+		"        AND relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        pg_class.oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        pg_attribute.attnum,"
+		"        pg_attribute.attacl"
+		"    FROM"
+		"        pg_class"
+		"        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
+		"    WHERE"
+		"        pg_attribute.attacl IS NOT NULL"
+		"        AND pg_class.relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),"
+		"        0,"
+		"        proacl"
+		"    FROM"
+		"        pg_proc"
+		"    WHERE"
+		"        proacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_type'),"
+		"        0,"
+		"        typacl"
+		"    FROM"
+		"        pg_type"
+		"    WHERE"
+		"        typacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_language'),"
+		"        0,"
+		"        lanacl"
+		"    FROM"
+		"        pg_language"
+		"    WHERE"
+		"        lanacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_largeobject_metadata'),"
+		"        0,"
+		"        lomacl"
+		"    FROM"
+		"        pg_largeobject_metadata"
+		"    WHERE"
+		"        lomacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),"
+		"        0,"
+		"        nspacl"
+		"    FROM"
+		"        pg_namespace"
+		"    WHERE"
+		"        nspacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_database'),"
+		"        0,"
+		"        datacl"
+		"    FROM"
+		"        pg_database"
+		"    WHERE"
+		"        datacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_tablespace'),"
+		"        0,"
+		"        spcacl"
+		"    FROM"
+		"        pg_tablespace"
+		"    WHERE"
+		"        spcacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_foreign_data_wrapper'),"
+		"        0,"
+		"        fdwacl"
+		"    FROM"
+		"        pg_foreign_data_wrapper"
+		"    WHERE"
+		"        fdwacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs (objoid, classoid, objsubid, initprivs)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class "
+		"		  WHERE relname = 'pg_foreign_server'),"
+		"        0,"
+		"        srvacl"
+		"    FROM"
+		"        pg_foreign_server"
+		"    WHERE"
+		"        srvacl IS NOT NULL;",
 		NULL
 	};
 
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index ab2c1a8..1a94f6d 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -162,6 +162,9 @@ DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using b
 DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhparent oid_ops));
 #define InheritsParentIndexId  2187
 
+DECLARE_UNIQUE_INDEX(pg_init_privs_o_c_o_index, 2740, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
+#define InitPrivsObjIndexId  2740
+
 DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops));
 #define LanguageNameIndexId  2681
 DECLARE_UNIQUE_INDEX(pg_language_oid_index, 2682, on pg_language using btree(oid oid_ops));
diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h
new file mode 100644
index 0000000..051ae90
--- /dev/null
+++ b/src/include/catalog/pg_init_privs.h
@@ -0,0 +1,83 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_init_privs.h
+ *	  definition of the system "initial privileges" relation (pg_init_privs)
+ *
+ * NOTE: an object is identified by the OID of the row that primarily
+ * defines the object, plus the OID of the table that that row appears in.
+ * For example, a function is identified by the OID of its pg_proc row
+ * plus the pg_class OID of table pg_proc.  This allows unique identification
+ * of objects without assuming that OIDs are unique across tables.
+ *
+ * Since attributes don't have OIDs of their own, we identify an attribute
+ * privilege by the objoid+classoid of its parent table, plus an "objsubid"
+ * giving the attribute column number.  "objsubid" must be zero in a privilege
+ * for a table itself, so that it is distinct from any column privilege.
+ * Currently, objsubid is unused and zero for all other kinds of objects.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_init_privs.h
+ *
+ * NOTES
+ *		the genbki.pl script reads this file and generates .bki
+ *		information from the DATA() statements.
+ *
+ *		XXX do NOT break up DATA() statements into multiple lines!
+ *			the scripts are not as smart as you might think...
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_INIT_PRIVS_H
+#define PG_INIT_PRIVS_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ *		pg_init_privs definition.  cpp turns this into
+ *		typedef struct FormData_pg_init_privs
+ * ----------------
+ */
+#define InitPrivsRelationId  2739
+
+CATALOG(pg_init_privs,2739) BKI_WITHOUT_OIDS
+{
+	Oid			objoid;			/* OID of object itself */
+	Oid			classoid;		/* OID of table containing object */
+	int32		objsubid;		/* column number, or 0 if not used */
+
+#ifdef CATALOG_VARLEN			/* variable-length fields start here */
+	aclitem initprivs[1] BKI_FORCE_NOT_NULL;	/* initial privs on object */
+#endif
+} FormData_pg_init_privs;
+
+/* ----------------
+ *		Form_pg_init_privs corresponds to a pointer to a tuple with
+ *		the format of pg_init_privs relation.
+ * ----------------
+ */
+typedef FormData_pg_init_privs *Form_pg_init_privs;
+
+/* ----------------
+ *		compiler constants for pg_init_privs
+ * ----------------
+ */
+#define Natts_pg_init_privs				4
+#define Anum_pg_init_privs_objoid		1
+#define Anum_pg_init_privs_classoid		2
+#define Anum_pg_init_privs_objsubid		3
+#define Anum_pg_init_privs_privs		4
+
+/* ----------------
+ *		initial contents of pg_init_privs
+ * ----------------
+ */
+
+/*
+ *	Because the contents of this table are taken from the other *.h files,
+ *	there is no initialization here.  The initial contents are loaded during
+ *	system_views.sql.
+ */
+
+#endif   /* PG_INIT_PRIVS_H */
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index eb0bc88..1c087a3 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -110,6 +110,7 @@ pg_foreign_server|t
 pg_foreign_table|t
 pg_index|t
 pg_inherits|t
+pg_init_privs|t
 pg_language|t
 pg_largeobject|t
 pg_largeobject_metadata|t
-- 
2.5.0


From dd96da1235bf0ab4db767412d5e5f6b5368981af Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:31:03 -0400
Subject: [PATCH 2/5] In pg_dump, use a bitmap to represent what to include

pg_dump has historically used a simple boolean 'dump' value to indicate
if a given object should be included in the dump or not.  Instead, use
a bitmap which breaks down the components of an object into their
distinct pieces and use that bitmap to only include the components
requested.

This does not include any behavioral change, but is in preperation for
the change to dump out just ACLs for objects in pg_catalog.
---
 src/bin/pg_dump/common.c  |    2 +-
 src/bin/pg_dump/pg_dump.c | 1518 ++++++++++++++++++++++++---------------------
 src/bin/pg_dump/pg_dump.h |   14 +-
 3 files changed, 841 insertions(+), 693 deletions(-)

diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index f798b15..507b0bf 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -437,7 +437,7 @@ AssignDumpId(DumpableObject *dobj)
 	dobj->dumpId = ++lastDumpId;
 	dobj->name = NULL;			/* must be set later */
 	dobj->namespace = NULL;		/* may be set later */
-	dobj->dump = true;			/* default assumption */
+	dobj->dump = DUMP_COMPONENT_ALL;	/* default assumption */
 	dobj->ext_member = false;	/* default assumption */
 	dobj->dependencies = NULL;
 	dobj->nDeps = 0;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 64c2673..08a2e93 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1284,7 +1284,7 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
 	 * extension contents with something different.
 	 */
 	if (!dopt->binary_upgrade)
-		dobj->dump = false;
+		dobj->dump = DUMP_COMPONENT_NONE;
 	else
 		dobj->dump = ext->dobj.dump;
 
@@ -1306,16 +1306,18 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 * namespaces. If specific namespaces are being dumped, dump just those
 	 * namespaces. Otherwise, dump all non-system namespaces.
 	 */
+
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
 		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
-												   nsinfo->dobj.catId.oid);
+								   nsinfo->dobj.catId.oid) ?
+							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = true;
+		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
@@ -1323,7 +1325,7 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	if (nsinfo->dobj.dump &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1342,7 +1344,8 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	 */
 	if (table_include_oids.head != NULL)
 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
-												   tbinfo->dobj.catId.oid);
+												   tbinfo->dobj.catId.oid) ?
+								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
 
@@ -1352,7 +1355,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	if (tbinfo->dobj.dump &&
 		simple_oid_list_member(&table_exclude_oids,
 							   tbinfo->dobj.catId.oid))
-		tbinfo->dobj.dump = false;
+		tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1381,7 +1384,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 		if (tytable != NULL)
 			tyinfo->dobj.dump = tytable->dobj.dump;
 		else
-			tyinfo->dobj.dump = false;
+			tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
 		return;
 	}
 
@@ -1401,11 +1404,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	/* dump only types in dumpable namespaces */
-	if (!tyinfo->dobj.namespace->dobj.dump)
-		tyinfo->dobj.dump = false;
-	else
-		tyinfo->dobj.dump = true;
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
 }
 
 /*
@@ -1424,7 +1423,8 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	if (dinfo->dobj.namespace)
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
-		dinfo->dobj.dump = dopt->include_everything;
+		dinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1443,9 +1443,10 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		cast->dobj.dump = false;
+		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		cast->dobj.dump = dopt->include_everything;
+		cast->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1463,9 +1464,10 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		plang->dobj.dump = false;
+		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = dopt->include_everything;
+		plang->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1482,9 +1484,10 @@ static void
 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 {
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = false;
+		extinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		extinfo->dobj.dump = dopt->include_everything;
+		extinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1506,7 +1509,8 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	if (dobj->namespace)
 		dobj->dump = dobj->namespace->dobj.dump;
 	else
-		dobj->dump = dopt->include_everything;
+		dobj->dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1911,13 +1915,14 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
 	 * dependency on its table as "special" and pass it to ArchiveEntry now.
 	 * See comments for BuildArchiveDependencies.
 	 */
-	ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
-				 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
-				 NULL, tbinfo->rolname,
-				 false, "TABLE DATA", SECTION_DATA,
-				 "", "", copyStmt,
-				 &(tbinfo->dobj.dumpId), 1,
-				 dumpFn, tdinfo);
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
+					 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
+					 NULL, tbinfo->rolname,
+					 false, "TABLE DATA", SECTION_DATA,
+					 "", "", copyStmt,
+					 &(tbinfo->dobj.dumpId), 1,
+					 dumpFn, tdinfo);
 
 	destroyPQExpBuffer(copyBuf);
 	destroyPQExpBuffer(clistBuf);
@@ -1945,23 +1950,24 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout,
-				 tdinfo->dobj.catId,	/* catalog ID */
-				 tdinfo->dobj.dumpId,	/* dump ID */
-				 tbinfo->dobj.name,		/* Name */
-				 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
-				 NULL,			/* Tablespace */
-				 tbinfo->rolname,		/* Owner */
-				 false,			/* with oids */
-				 "MATERIALIZED VIEW DATA",		/* Desc */
-				 SECTION_POST_DATA,		/* Section */
-				 q->data,		/* Create */
-				 "",			/* Del */
-				 NULL,			/* Copy */
-				 tdinfo->dobj.dependencies,		/* Deps */
-				 tdinfo->dobj.nDeps,	/* # Deps */
-				 NULL,			/* Dumper */
-				 NULL);			/* Dumper Arg */
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout,
+					 tdinfo->dobj.catId,	/* catalog ID */
+					 tdinfo->dobj.dumpId,	/* dump ID */
+					 tbinfo->dobj.name,		/* Name */
+					 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
+					 NULL,			/* Tablespace */
+					 tbinfo->rolname,		/* Owner */
+					 false,			/* with oids */
+					 "MATERIALIZED VIEW DATA",		/* Desc */
+					 SECTION_POST_DATA,		/* Section */
+					 q->data,		/* Create */
+					 "",			/* Del */
+					 NULL,			/* Copy */
+					 tdinfo->dobj.dependencies,		/* Deps */
+					 tdinfo->dobj.nDeps,	/* # Deps */
+					 NULL,			/* Dumper */
+					 NULL);			/* Dumper Arg */
 
 	destroyPQExpBuffer(q);
 }
@@ -1977,7 +1983,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids)
 
 	for (i = 0; i < numTables; i++)
 	{
-		if (tblinfo[i].dobj.dump)
+		if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA)
 			makeTableDataInfo(dopt, &(tblinfo[i]), oids);
 	}
 }
@@ -2238,7 +2244,7 @@ guessConstraintInheritance(TableInfo *tblinfo, int numTables)
 			continue;
 
 		/* Don't bother computing anything for non-target tables, either */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		numParents = tbinfo->numParents;
@@ -2788,31 +2794,34 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 					  "SELECT pg_catalog.lo_unlink('%s');\n",
 					  binfo->dobj.name);
 
-	ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
-				 binfo->dobj.name,
-				 NULL, NULL,
-				 binfo->rolname, false,
-				 "BLOB", SECTION_PRE_DATA,
-				 cquery->data, dquery->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
+					 binfo->dobj.name,
+					 NULL, NULL,
+					 binfo->rolname, false,
+					 "BLOB", SECTION_PRE_DATA,
+					 cquery->data, dquery->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* set up tag for comment and/or ACL */
 	resetPQExpBuffer(cquery);
 	appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
 
 	/* Dump comment if any */
-	dumpComment(fout, cquery->data,
-				NULL, binfo->rolname,
-				binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, cquery->data,
+					NULL, binfo->rolname,
+					binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump security label if any */
-	dumpSecLabel(fout, cquery->data,
-				 NULL, binfo->rolname,
-				 binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, cquery->data,
+					 NULL, binfo->rolname,
+					 binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump ACL if any */
-	if (binfo->blobacl)
+	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
 		dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 				binfo->dobj.name, NULL, cquery->data,
 				NULL, binfo->rolname, binfo->blobacl);
@@ -2933,7 +2942,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
 		TableInfo  *tbinfo = &tblinfo[i];
 
 		/* Ignore row security on tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
 			continue;
 
 		if (g_verbose)
@@ -3073,15 +3082,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 		appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
 						  fmtId(polinfo->dobj.name));
 
-		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-					 polinfo->dobj.name,
-					 polinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "ROW SECURITY", SECTION_POST_DATA,
-					 query->data, "", NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+			ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+						 polinfo->dobj.name,
+						 polinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "ROW SECURITY", SECTION_POST_DATA,
+						 query->data, "", NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
 		destroyPQExpBuffer(query);
 		return;
@@ -3124,15 +3134,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 	appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
 	appendPQExpBuffer(delqry, " ON %s;\n", fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-				 polinfo->dobj.name,
-				 polinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "POLICY", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+					 polinfo->dobj.name,
+					 polinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "POLICY", SECTION_POST_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -3737,7 +3748,8 @@ getTypes(Archive *fout, int *numTypes)
 		 */
 		tyinfo[i].nDomChecks = 0;
 		tyinfo[i].domChecks = NULL;
-		if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			tyinfo[i].typtype == TYPTYPE_DOMAIN)
 			getDomainConstraints(fout, &(tyinfo[i]));
 
 		/*
@@ -3750,8 +3762,9 @@ getTypes(Archive *fout, int *numTypes)
 		 * should copy the base type's catId, but then it might capture the
 		 * pg_depend entries for the type, which we don't want.
 		 */
-		if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
-									tyinfo[i].typtype == TYPTYPE_RANGE))
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			(tyinfo[i].typtype == TYPTYPE_BASE ||
+			 tyinfo[i].typtype == TYPTYPE_RANGE))
 		{
 			stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
 			stinfo->dobj.objType = DO_SHELL_TYPE;
@@ -3767,7 +3780,7 @@ getTypes(Archive *fout, int *numTypes)
 			 * dump it if the I/O or canonicalize functions need to be dumped;
 			 * this is taken care of while sorting dependencies.
 			 */
-			stinfo->dobj.dump = false;
+			stinfo->dobj.dump = DUMP_COMPONENT_NONE;
 
 			/*
 			 * However, if dumping from pre-7.3, there will be no dependency
@@ -3785,7 +3798,7 @@ getTypes(Archive *fout, int *numTypes)
 				typoutput = atooid(PQgetvalue(res, i, i_typoutput));
 
 				funcInfo = findFuncByOid(typinput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3794,11 +3807,11 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 
 				funcInfo = findFuncByOid(typoutput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3807,7 +3820,7 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 			}
 		}
@@ -5255,10 +5268,11 @@ getTables(Archive *fout, int *numTables)
 		 * Decide whether we want to dump this table.
 		 */
 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
-			tblinfo[i].dobj.dump = false;
+			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
 		else
 			selectDumpableTable(&tblinfo[i], dopt);
-		tblinfo[i].interesting = tblinfo[i].dobj.dump;
+
+		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
 
@@ -5325,13 +5339,13 @@ getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
 
 		if (!OidIsValid(seqinfo->owning_tab))
 			continue;			/* not an owned sequence */
-		if (seqinfo->dobj.dump)
+		if (seqinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			continue;			/* no need to search */
 		owning_tab = findTableByOid(seqinfo->owning_tab);
 		if (owning_tab && owning_tab->dobj.dump)
 		{
 			seqinfo->interesting = true;
-			seqinfo->dobj.dump = true;
+			seqinfo->dobj.dump = DUMP_COMPONENT_ALL;
 		}
 	}
 }
@@ -5433,8 +5447,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 		if (!tbinfo->hasindex)
 			continue;
 
-		/* Ignore indexes of tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		/* Ignore indexes of tables whose definitions are not to be dumped */
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -5801,7 +5815,8 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -6140,7 +6155,8 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -8490,12 +8506,13 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
 			dumpBlob(fout, (BlobInfo *) dobj);
 			break;
 		case DO_BLOB_DATA:
-			ArchiveEntry(fout, dobj->catId, dobj->dumpId,
-						 dobj->name, NULL, NULL, "",
-						 false, "BLOBS", SECTION_DATA,
-						 "", "", NULL,
-						 NULL, 0,
-						 dumpBlobs, NULL);
+			if (dobj->dump & DUMP_COMPONENT_DATA)
+				ArchiveEntry(fout, dobj->catId, dobj->dumpId,
+							 dobj->name, NULL, NULL, "",
+							 false, "BLOBS", SECTION_DATA,
+							 "", "", NULL,
+							 NULL, 0,
+							 dumpBlobs, NULL);
 			break;
 		case DO_POLICY:
 			dumpPolicy(fout, (PolicyInfo *) dobj);
@@ -8543,26 +8560,31 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
-				 nspinfo->dobj.name,
-				 NULL, NULL,
-				 nspinfo->rolname,
-				 false, "SCHEMA", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
+					 nspinfo->dobj.name,
+					 NULL, NULL,
+					 nspinfo->rolname,
+					 false, "SCHEMA", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Schema Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, nspinfo->rolname,
-				nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, nspinfo->rolname,
-				 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, nspinfo->rolname,
+					nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, nspinfo->rolname,
+					 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
 
-	dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
-			qnspname, NULL, nspinfo->dobj.name, NULL,
-			nspinfo->rolname, nspinfo->nspacl);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
+				qnspname, NULL, nspinfo->dobj.name, NULL,
+				nspinfo->rolname, nspinfo->nspacl);
 
 	free(qnspname);
 
@@ -8672,22 +8694,26 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
 	appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
 
-	ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
-				 extinfo->dobj.name,
-				 NULL, NULL,
-				 "",
-				 false, "EXTENSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
+					 extinfo->dobj.name,
+					 NULL, NULL,
+					 "",
+					 false, "EXTENSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Extension Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+
+	if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
 
 	free(qextname);
 
@@ -8827,28 +8853,33 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -8960,28 +8991,33 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9030,28 +9066,33 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -9419,28 +9460,33 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9582,28 +9628,33 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "DOMAIN", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "DOMAIN", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Domain Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	/* Dump any per-constraint comments */
 	for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9615,10 +9666,13 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 						  fmtId(domcheck->dobj.name));
 		appendPQExpBuffer(labelq, "ON DOMAIN %s",
 						  qtypname);
-		dumpComment(fout, labelq->data,
-					tyinfo->dobj.namespace->dobj.name,
-					tyinfo->rolname,
-					domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+		if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpComment(fout, labelq->data,
+						tyinfo->dobj.namespace->dobj.name,
+						tyinfo->rolname,
+						domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
 		destroyPQExpBuffer(labelq);
 	}
 
@@ -9808,29 +9862,34 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9840,7 +9899,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	destroyPQExpBuffer(query);
 
 	/* Dump any per-column comments */
-	dumpCompositeTypeColComments(fout, tyinfo);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpCompositeTypeColComments(fout, tyinfo);
 }
 
 /*
@@ -9985,15 +10045,16 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
 					  fmtId(stinfo->dobj.name));
 
-	ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
-				 stinfo->dobj.name,
-				 stinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 stinfo->baseType->rolname, false,
-				 "SHELL TYPE", SECTION_PRE_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
+					 stinfo->dobj.name,
+					 stinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 stinfo->baseType->rolname, false,
+					 "SHELL TYPE", SECTION_PRE_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 }
@@ -10122,23 +10183,27 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
 
-	ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
-				 plang->dobj.name,
-				 lanschema, NULL, plang->lanowner,
-				 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
+					 plang->dobj.name,
+					 lanschema, NULL, plang->lanowner,
+					 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Proc Lang Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				plang->dobj.catId, 0, plang->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 plang->dobj.catId, 0, plang->dobj.dumpId);
-
-	if (plang->lanpltrusted)
+	if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					plang->dobj.catId, 0, plang->dobj.dumpId);
+
+	if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 plang->dobj.catId, 0, plang->dobj.dumpId);
+
+	if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 				qlanname, NULL, plang->dobj.name,
 				lanschema,
@@ -10787,28 +10852,33 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
-				 funcsig_tag,
-				 finfo->dobj.namespace->dobj.name,
-				 NULL,
-				 finfo->rolname, false,
-				 "FUNCTION", SECTION_PRE_DATA,
-				 q->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
+					 funcsig_tag,
+					 finfo->dobj.namespace->dobj.name,
+					 NULL,
+					 finfo->rolname, false,
+					 "FUNCTION", SECTION_PRE_DATA,
+					 q->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Function Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				finfo->dobj.namespace->dobj.name, finfo->rolname,
-				finfo->dobj.catId, 0, finfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 finfo->dobj.namespace->dobj.name, finfo->rolname,
-				 finfo->dobj.catId, 0, finfo->dobj.dumpId);
-
-	dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
-			funcsig, NULL, funcsig_tag,
-			finfo->dobj.namespace->dobj.name,
-			finfo->rolname, finfo->proacl);
+	if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					finfo->dobj.namespace->dobj.name, finfo->rolname,
+					finfo->dobj.catId, 0, finfo->dobj.dumpId);
+
+	if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 finfo->dobj.namespace->dobj.name, finfo->rolname,
+					 finfo->dobj.catId, 0, finfo->dobj.dumpId);
+
+	if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
+				funcsig, NULL, funcsig_tag,
+				finfo->dobj.namespace->dobj.name,
+				finfo->rolname, finfo->proacl);
 
 	PQclear(res);
 
@@ -10917,18 +10987,20 @@ dumpCast(Archive *fout, CastInfo *cast)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
 
-	ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "CAST", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "CAST", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Cast Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				cast->dobj.catId, 0, cast->dobj.dumpId);
+	if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					cast->dobj.catId, 0, cast->dobj.dumpId);
 
 	free(sourceType);
 	free(targetType);
@@ -11037,18 +11109,20 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &transform->dobj, labelq->data);
 
-	ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "TRANSFORM", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 transform->dobj.dependencies, transform->dobj.nDeps,
-				 NULL, NULL);
+	if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "TRANSFORM", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 transform->dobj.dependencies, transform->dobj.nDeps,
+					 NULL, NULL);
 
 	/* Dump Transform Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				transform->dobj.catId, 0, transform->dobj.dumpId);
+	if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					transform->dobj.catId, 0, transform->dobj.dumpId);
 
 	free(lanname);
 	free(transformType);
@@ -11291,20 +11365,22 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
-				 oprinfo->dobj.name,
-				 oprinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 oprinfo->rolname,
-				 false, "OPERATOR", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
+					 oprinfo->dobj.name,
+					 oprinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 oprinfo->rolname,
+					 false, "OPERATOR", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Comments */
-	dumpComment(fout, labelq->data,
-				oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
-				oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
+					oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -11800,20 +11876,22 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
-				 opcinfo->dobj.name,
-				 opcinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opcinfo->rolname,
-				 false, "OPERATOR CLASS", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
+					 opcinfo->dobj.name,
+					 opcinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opcinfo->rolname,
+					 false, "OPERATOR CLASS", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Class Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opcinfo->rolname,
-				opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opcinfo->rolname,
+					opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
 
 	free(amname);
 	destroyPQExpBuffer(query);
@@ -12114,20 +12192,22 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
-				 opfinfo->dobj.name,
-				 opfinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opfinfo->rolname,
-				 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
+					 opfinfo->dobj.name,
+					 opfinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opfinfo->rolname,
+					 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Family Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opfinfo->rolname,
-				opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opfinfo->rolname,
+					opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
 
 	free(amname);
 	PQclear(res_ops);
@@ -12204,20 +12284,22 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
-				 collinfo->dobj.name,
-				 collinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 collinfo->rolname,
-				 false, "COLLATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
+					 collinfo->dobj.name,
+					 collinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 collinfo->rolname,
+					 false, "COLLATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Collation Comments */
-	dumpComment(fout, labelq->data,
-				collinfo->dobj.namespace->dobj.name, collinfo->rolname,
-				collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					collinfo->dobj.namespace->dobj.name, collinfo->rolname,
+					collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12304,20 +12386,22 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
-				 convinfo->dobj.name,
-				 convinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 convinfo->rolname,
-				 false, "CONVERSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
+					 convinfo->dobj.name,
+					 convinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 convinfo->rolname,
+					 false, "CONVERSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Conversion Comments */
-	dumpComment(fout, labelq->data,
-				convinfo->dobj.namespace->dobj.name, convinfo->rolname,
-				convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					convinfo->dobj.namespace->dobj.name, convinfo->rolname,
+					convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12731,23 +12815,30 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
 
-	ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-				 aggsig_tag,
-				 agginfo->aggfn.dobj.namespace->dobj.name,
-				 NULL,
-				 agginfo->aggfn.rolname,
-				 false, "AGGREGATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
+					 agginfo->aggfn.dobj.dumpId,
+					 aggsig_tag,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 NULL,
+					 agginfo->aggfn.rolname,
+					 false, "AGGREGATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Aggregate Comments */
-	dumpComment(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					agginfo->aggfn.dobj.namespace->dobj.name,
+					agginfo->aggfn.rolname,
+					agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 agginfo->aggfn.rolname,
+					 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
 	/*
 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
@@ -12760,11 +12851,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	aggsig = format_function_signature(fout, &agginfo->aggfn, true);
 	aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
 
-	dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-			"FUNCTION",
-			aggsig, NULL, aggsig_tag,
-			agginfo->aggfn.dobj.namespace->dobj.name,
-			agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
+				"FUNCTION",
+				aggsig, NULL, aggsig_tag,
+				agginfo->aggfn.dobj.namespace->dobj.name,
+				agginfo->aggfn.rolname, agginfo->aggfn.proacl);
 
 	free(aggsig);
 	if (aggfullsig)
@@ -12832,20 +12924,22 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
-				 prsinfo->dobj.name,
-				 prsinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
+					 prsinfo->dobj.name,
+					 prsinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Parser Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -12920,20 +13014,22 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
-				 dictinfo->dobj.name,
-				 dictinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 dictinfo->rolname,
-				 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
+					 dictinfo->dobj.name,
+					 dictinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 dictinfo->rolname,
+					 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Dictionary Comments */
-	dumpComment(fout, labelq->data,
-				NULL, dictinfo->rolname,
-				dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, dictinfo->rolname,
+					dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -12987,20 +13083,22 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
-				 tmplinfo->dobj.name,
-				 tmplinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
+					 tmplinfo->dobj.name,
+					 tmplinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Template Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13116,20 +13214,22 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
-				 cfginfo->dobj.name,
-				 cfginfo->dobj.namespace->dobj.name,
-				 NULL,
-				 cfginfo->rolname,
-				 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
+					 cfginfo->dobj.name,
+					 cfginfo->dobj.namespace->dobj.name,
+					 NULL,
+					 cfginfo->rolname,
+					 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Configuration Comments */
-	dumpComment(fout, labelq->data,
-				NULL, cfginfo->rolname,
-				cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, cfginfo->rolname,
+					cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13183,27 +13283,30 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-				 fdwinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 fdwinfo->rolname,
-				 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+					 fdwinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 fdwinfo->rolname,
+					 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-			"FOREIGN DATA WRAPPER",
-			qfdwname, NULL, fdwinfo->dobj.name,
-			NULL, fdwinfo->rolname,
-			fdwinfo->fdwacl);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+				"FOREIGN DATA WRAPPER",
+				qfdwname, NULL, fdwinfo->dobj.name,
+				NULL, fdwinfo->rolname,
+				fdwinfo->fdwacl);
 
 	/* Dump Foreign Data Wrapper Comments */
-	dumpComment(fout, labelq->data,
-				NULL, fdwinfo->rolname,
-				fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, fdwinfo->rolname,
+					fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
 
 	free(qfdwname);
 
@@ -13276,33 +13379,37 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-				 srvinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 srvinfo->rolname,
-				 false, "SERVER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+					 srvinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 srvinfo->rolname,
+					 false, "SERVER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-			"FOREIGN SERVER",
-			qsrvname, NULL, srvinfo->dobj.name,
-			NULL, srvinfo->rolname,
-			srvinfo->srvacl);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+				"FOREIGN SERVER",
+				qsrvname, NULL, srvinfo->dobj.name,
+				NULL, srvinfo->rolname,
+				srvinfo->srvacl);
 
 	/* Dump user mappings */
-	dumpUserMappings(fout,
-					 srvinfo->dobj.name, NULL,
-					 srvinfo->rolname,
-					 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
+		dumpUserMappings(fout,
+						 srvinfo->dobj.name, NULL,
+						 srvinfo->rolname,
+						 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
 
 	/* Dump Foreign Server Comments */
-	dumpComment(fout, labelq->data,
-				NULL, srvinfo->rolname,
-				srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, srvinfo->rolname,
+					srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
 
 	free(qsrvname);
 
@@ -13465,15 +13572,16 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 		exit_horribly(NULL, "could not parse default ACL list (%s)\n",
 					  daclinfo->defaclacl);
 
-	ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
-				 tag->data,
+	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
+					 tag->data,
 	   daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
-				 NULL,
-				 daclinfo->defaclrole,
-				 false, "DEFAULT ACL", SECTION_POST_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 NULL,
+					 daclinfo->defaclrole,
+					 false, "DEFAULT ACL", SECTION_POST_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(tag);
 	destroyPQExpBuffer(q);
@@ -13842,19 +13950,16 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
 static void
 dumpTable(Archive *fout, TableInfo *tbinfo)
 {
-	DumpOptions *dopt = fout->dopt;
+	char		   *namecopy;
 
-	if (tbinfo->dobj.dump && !dopt->dataOnly)
-	{
-		char	   *namecopy;
-
-		if (tbinfo->relkind == RELKIND_SEQUENCE)
-			dumpSequence(fout, tbinfo);
-		else
-			dumpTableSchema(fout, tbinfo);
+	if (tbinfo->relkind == RELKIND_SEQUENCE)
+		dumpSequence(fout, tbinfo);
+	else
+		dumpTableSchema(fout, tbinfo);
 
-		/* Handle the ACL here */
-		namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	/* Handle the ACL here */
+	namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 				(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
 				"TABLE",
@@ -13862,47 +13967,49 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 				tbinfo->relacl);
 
-		/*
-		 * Handle column ACLs, if any.  Note: we pull these with a separate
-		 * query rather than trying to fetch them during getTableAttrs, so
-		 * that we won't miss ACLs on system columns.
-		 */
-		if (fout->remoteVersion >= 80400)
-		{
-			PQExpBuffer query = createPQExpBuffer();
-			PGresult   *res;
-			int			i;
+	/*
+	 * Handle column ACLs, if any.  Note: we pull these with a separate
+	 * query rather than trying to fetch them during getTableAttrs, so
+	 * that we won't miss ACLs on system columns.
+	 */
+	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
+	{
+		PQExpBuffer query = createPQExpBuffer();
+		PGresult   *res;
+		int			i;
 
-			appendPQExpBuffer(query,
-					   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
-							  "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
-							  "ORDER BY attnum",
-							  tbinfo->dobj.catId.oid);
-			res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+		appendPQExpBuffer(query,
+				   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
+						  "WHERE attrelid = '%u' AND NOT attisdropped "
+						  "AND attacl IS NOT NULL "
+						  "ORDER BY attnum",
+						  tbinfo->dobj.catId.oid);
+		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
-			for (i = 0; i < PQntuples(res); i++)
-			{
-				char	   *attname = PQgetvalue(res, i, 0);
-				char	   *attacl = PQgetvalue(res, i, 1);
-				char	   *attnamecopy;
-				char	   *acltag;
-
-				attnamecopy = pg_strdup(fmtId(attname));
-				acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
-				/* Column's GRANT type is always TABLE */
-				dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
-						namecopy, attnamecopy, acltag,
-						tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-						attacl);
-				free(attnamecopy);
-				free(acltag);
-			}
-			PQclear(res);
-			destroyPQExpBuffer(query);
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			char	   *attname = PQgetvalue(res, i, 0);
+			char	   *attacl = PQgetvalue(res, i, 1);
+			char	   *attnamecopy;
+			char	   *acltag;
+
+			attnamecopy = pg_strdup(fmtId(attname));
+			acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
+			/* Column's GRANT type is always TABLE */
+			dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
+					namecopy, attnamecopy, acltag,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					attacl);
+			free(attnamecopy);
+			free(acltag);
 		}
-
-		free(namecopy);
+		PQclear(res);
+		destroyPQExpBuffer(query);
 	}
+
+	free(namecopy);
+
+	return;
 }
 
 /*
@@ -14580,24 +14687,28 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
 			(tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
-				 tbinfo->rolname,
+					 tbinfo->rolname,
 			   (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
-				 reltypename,
-				 tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 reltypename,
+					 tbinfo->postponed_def ?
+						SECTION_POST_DATA : SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Table Comments */
-	dumpTableComment(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpTableComment(fout, tbinfo, reltypename);
 
 	/* Dump Table Security Labels */
-	dumpTableSecLabel(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpTableSecLabel(fout, tbinfo, reltypename);
 
 	/* Dump comments on inlined table constraints */
 	for (j = 0; j < tbinfo->ncheck; j++)
@@ -14607,7 +14718,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		if (constr->separate || !constr->conislocal)
 			continue;
 
-		dumpTableConstraintComment(fout, constr);
+		if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpTableConstraintComment(fout, constr);
 	}
 
 	destroyPQExpBuffer(q);
@@ -14654,15 +14766,16 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 	appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
 					  fmtId(tbinfo->attnames[adnum - 1]));
 
-	ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
-				 tbinfo->attnames[adnum - 1],
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "DEFAULT", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
+					 tbinfo->attnames[adnum - 1],
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "DEFAULT", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -14769,24 +14882,26 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 		appendPQExpBuffer(delq, "%s;\n",
 						  fmtId(indxinfo->dobj.name));
 
-		ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
-					 indxinfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "INDEX", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
+						 indxinfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "INDEX", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 
 	/* Dump Index Comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				indxinfo->dobj.catId, 0,
-				is_constraint ? indxinfo->indexconstraint :
-				indxinfo->dobj.dumpId);
+	if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					indxinfo->dobj.catId, 0,
+					is_constraint ? indxinfo->indexconstraint :
+					indxinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -14897,15 +15012,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'f')
 	{
@@ -14930,15 +15046,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "FK CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "FK CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'c' && tbinfo)
 	{
@@ -14965,15 +15082,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else if (coninfo->contype == 'c' && tbinfo == NULL)
@@ -15001,15 +15119,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tyinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tyinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tyinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tyinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else
@@ -15019,7 +15138,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 	}
 
 	/* Dump Constraint Comments --- only works for table constraints */
-	if (tbinfo && coninfo->separate)
+	if (tbinfo && coninfo->separate &&
+		coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
 		dumpTableConstraintComment(fout, coninfo);
 
 	destroyPQExpBuffer(q);
@@ -15043,10 +15163,12 @@ dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
 					  fmtId(coninfo->dobj.name));
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				coninfo->dobj.catId, 0,
+
+	if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					coninfo->dobj.catId, 0,
 			 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(labelq);
@@ -15241,15 +15363,16 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 		binary_upgrade_extension_member(query, &tbinfo->dobj,
 										labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE", SECTION_PRE_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE", SECTION_PRE_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/*
 	 * If the sequence is owned by a table column, emit the ALTER for it as a
@@ -15277,25 +15400,29 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 			appendPQExpBuffer(query, ".%s;\n",
 						fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
 
-			ArchiveEntry(fout, nilCatalogId, createDumpId(),
-						 tbinfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname,
-						 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
-						 query->data, "", NULL,
-						 &(tbinfo->dobj.dumpId), 1,
-						 NULL, NULL);
+			if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, nilCatalogId, createDumpId(),
+							 tbinfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname,
+							 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
+							 query->data, "", NULL,
+							 &(tbinfo->dobj.dumpId), 1,
+							 NULL, NULL);
 		}
 	}
 
 	/* Dump Sequence Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -15344,15 +15471,16 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(query, ", %s, %s);\n",
 					  last, (called ? "true" : "false"));
 
-	ArchiveEntry(fout, nilCatalogId, createDumpId(),
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE SET", SECTION_DATA,
-				 query->data, "", NULL,
-				 &(tbinfo->dobj.dumpId), 1,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, nilCatalogId, createDumpId(),
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE SET", SECTION_DATA,
+					 query->data, "", NULL,
+					 &(tbinfo->dobj.dumpId), 1,
+					 NULL, NULL);
 
 	PQclear(res);
 
@@ -15551,19 +15679,21 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
-				 tginfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "TRIGGER", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
+						 tginfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "TRIGGER", SECTION_POST_DATA,
+						 query->data, delqry->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -15628,14 +15758,16 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
 	appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
 					  fmtId(evtinfo->dobj.name));
 
-	ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
-				 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
-				 "EVENT TRIGGER", SECTION_POST_DATA,
-				 query->data, "", NULL, NULL, 0, NULL, NULL);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
+					 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
+					 "EVENT TRIGGER", SECTION_POST_DATA,
+					 query->data, "", NULL, NULL, 0, NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				NULL, evtinfo->evtowner,
-				evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, evtinfo->evtowner,
+					evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(labelq);
@@ -15752,21 +15884,23 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 	appendPQExpBuffer(labelq, " ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
-				 rinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "RULE", SECTION_POST_DATA,
-				 cmd->data, delcmd->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
+					 rinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "RULE", SECTION_POST_DATA,
+					 cmd->data, delcmd->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump rule comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -15940,7 +16074,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 			{
 				TableInfo  *configtbl;
 				Oid			configtbloid = atooid(extconfigarray[j]);
-				bool		dumpobj = curext->dobj.dump;
+				bool		dumpobj =
+								curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
 
 				configtbl = findTableByOid(configtbloid);
 				if (configtbl == NULL)
@@ -15950,7 +16085,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 				 * Tables of not-to-be-dumped extensions shouldn't be dumped
 				 * unless the table or its schema is explicitly included
 				 */
-				if (!curext->dobj.dump)
+				if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
 				{
 					/* check table explicitly requested */
 					if (table_include_oids.head != NULL &&
@@ -15959,7 +16094,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 						dumpobj = true;
 
 					/* check table's schema explicitly requested */
-					if (configtbl->dobj.namespace->dobj.dump)
+					if (configtbl->dobj.namespace->dobj.dump &
+							DUMP_COMPONENT_DATA)
 						dumpobj = true;
 				}
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 9a1d8f8..fd94d87 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -80,6 +80,18 @@ typedef enum
 	DO_POLICY
 } DumpableObjectType;
 
+/* component types of an object which can be selected for dumping */
+typedef uint32 DumpComponents;	/* a bitmask of dump object components */
+#define DUMP_COMPONENT_NONE			(0)
+#define DUMP_COMPONENT_DEFINITION	(1 << 0)
+#define DUMP_COMPONENT_DATA			(1 << 1)
+#define DUMP_COMPONENT_COMMENT		(1 << 2)
+#define DUMP_COMPONENT_SECLABEL		(1 << 3)
+#define DUMP_COMPONENT_ACL			(1 << 4)
+#define DUMP_COMPONENT_POLICY		(1 << 5)
+#define DUMP_COMPONENT_USERMAP		(1 << 6)
+#define DUMP_COMPONENT_ALL			(0xFFFF)
+
 typedef struct _dumpableObject
 {
 	DumpableObjectType objType;
@@ -87,7 +99,7 @@ typedef struct _dumpableObject
 	DumpId		dumpId;			/* assigned by AssignDumpId() */
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
-	bool		dump;			/* true if we want to dump this object */
+	DumpComponents dump;	/* bitmask of components to dump */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From 88e804d31c3ab9e880d559d260b736b90f6e75c7 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:44:21 -0400
Subject: [PATCH 3/5] In pg_dump, split "dump" into "dump" and "dump_contains"

Historically, the "dump" component of the namespace has been used
to decide if the objects inside of the namespace should be dumped
also.  Given that "dump" is now a bitmask and may be partial, and
we may want to dump out all components of the namespace object but
only some of the components of objects contained in the namespace,
create a "dump_contains" bitmask which will represent what components
of the objects inside of a namespace should be dumped out.

No behavior change here, but in preparation for a change where we
will dump out just the ACLs of objects in pg_catalog, but we might
not dump out the ACL of the pg_catalog namespace itself (for instance,
when it hasn't been changed from the value set at initdb time).
---
 src/bin/pg_dump/pg_dump.c | 21 ++++++++++++---------
 src/bin/pg_dump/pg_dump.h |  1 +
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 08a2e93..f02a6b9 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1308,24 +1308,25 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 */
 
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
-		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
+			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
 							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
 	 */
-	if (nsinfo->dobj.dump &&
+	if (nsinfo->dobj.dump_contains &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1347,7 +1348,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 												   tbinfo->dobj.catId.oid) ?
 								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
-		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
+		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
 
 	/*
 	 * In any case, a table can be excluded by an exclusion switch
@@ -1404,7 +1405,8 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
+	/* Dump based on if the contents of the namespace are being dumped */
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
 }
 
 /*
@@ -1421,6 +1423,7 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	/* Default ACLs can't be extension members */
 
 	if (dinfo->dobj.namespace)
+		/* default ACLs are considered part of the namespace */
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
 		dinfo->dobj.dump = dopt->include_everything ?
@@ -1507,7 +1510,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	 * non-namespace-associated items, dump if we're dumping "everything".
 	 */
 	if (dobj->namespace)
-		dobj->dump = dobj->namespace->dobj.dump;
+		dobj->dump = dobj->namespace->dobj.dump_contains;
 	else
 		dobj->dump = dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index fd94d87..508e6b9 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -100,6 +100,7 @@ typedef struct _dumpableObject
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
 	DumpComponents dump;	/* bitmask of components to dump */
+	DumpComponents dump_contains;	/* as above, but for contained objects */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From 51771180db220aabb3e7bde688ca91017e1a32e1 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 12:43:24 -0400
Subject: [PATCH 4/5] In pg_dump, include the ACLs in pg_catalog, when changed

Now that all of the infrastructure exists, add in the ability to
dump out the ACLs of the objects inside of pg_catalog, but only
if they have been changed from their original values.

The original values are tracked in pg_init_privs.  When pg_dump'ing
9.6-and-above databases, we will dump out the ACLs for any objects
in pg_catalog where the ACL has been changed from the original value
which was set during initdb.

The checks against pg_init_privs are pretty general and should work
also for extensions, though we don't yet provide a way for an
extension to populate pg_init_privs.

This should not change dumps against pre-9.6 databases.
---
 src/bin/pg_dump/pg_dump.c | 403 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 341 insertions(+), 62 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index f02a6b9..3ffb9a4 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1296,9 +1296,9 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
  *		Mark a namespace as to be dumped or not
  */
 static void
-selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
+selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
 {
-	if (checkExtensionMembership(&nsinfo->dobj, dopt))
+	if (checkExtensionMembership(&nsinfo->dobj, fout->dopt))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1314,6 +1314,14 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
 							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+	else if (fout->remoteVersion >= 90600 &&
+			 strncmp(nsinfo->dobj.name, "pg_catalog", 10) == 0)
+		/*
+		 * In 9.6 and above, we dump out any ACLs defined in pg_catalog,
+		 * if they are interesting (and not the original ACLs which were
+		 * set at initdb time, see pg_init_privs).
+		 */
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
@@ -3347,7 +3355,6 @@ binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
 NamespaceInfo *
 getNamespaces(Archive *fout, int *numNamespaces)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -3358,6 +3365,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	int			i_nspname;
 	int			i_rolname;
 	int			i_nspacl;
+	int			i_dumpacl;
 
 	/*
 	 * Before 7.3, there are no real namespaces; create two dummy entries, one
@@ -3375,7 +3383,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[0].rolname = pg_strdup("");
 		nsinfo[0].nspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[0], dopt);
+		selectDumpableNamespace(&nsinfo[0], fout);
 
 		nsinfo[1].dobj.objType = DO_NAMESPACE;
 		nsinfo[1].dobj.catId.tableoid = 0;
@@ -3385,7 +3393,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[1].rolname = pg_strdup("");
 		nsinfo[1].nspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[1], dopt);
+		selectDumpableNamespace(&nsinfo[1], fout);
 
 		*numNamespaces = 2;
 
@@ -3401,10 +3409,23 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	 * we fetch all namespaces including system ones, so that every object we
 	 * read in can be linked to a containing namespace.
 	 */
-	appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
-					  "(%s nspowner) AS rolname, "
-					  "nspacl FROM pg_namespace",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+		appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "n.nspacl, "
+					  "CASE WHEN pip.initprivs IS NOT DISTINCT FROM n.nspacl "
+						  "THEN false ELSE true END as dumpacl "
+						  "FROM pg_namespace n "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (n.oid = pip.objoid AND pip.classoid = "
+					"(SELECT oid FROM pg_class WHERE relname = 'pg_namespace') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery);
+	else
+		appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "nspacl, true as dumpacl FROM pg_namespace",
+						  username_subquery);
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -3417,6 +3438,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	i_nspname = PQfnumber(res, "nspname");
 	i_rolname = PQfnumber(res, "rolname");
 	i_nspacl = PQfnumber(res, "nspacl");
+	i_dumpacl = PQfnumber(res, "dumpacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -3429,7 +3451,11 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
 
 		/* Decide whether to dump this namespace */
-		selectDumpableNamespace(&nsinfo[i], dopt);
+		selectDumpableNamespace(&nsinfo[i], fout);
+
+		/* Decide if we dump the ACL for this namespace */
+		if (strcmp(PQgetvalue(res, i, i_dumpacl), "f") == 0)
+			nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(nsinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
@@ -3598,6 +3624,7 @@ getTypes(Archive *fout, int *numTypes)
 	int			i_typtype;
 	int			i_typisdefined;
 	int			i_isarray;
+	int			i_dumpacl;
 
 	/*
 	 * we include even the built-in types because those may be used as array
@@ -3618,7 +3645,28 @@ getTypes(Archive *fout, int *numTypes)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90200)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
+						  "t.typnamespace, t.typacl, "
+						  "(%s t.typowner) AS rolname, "
+						  "t.typinput::oid AS typinput, "
+						  "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, "
+						  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
+						  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
+						  "t.typtype, t.typisdefined, "
+						  "t.typname[0] = '_' AND t.typelem != 0 AND "
+						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray, "
+					  "CASE WHEN pip.initprivs IS NOT DISTINCT FROM t.typacl "
+						  "THEN false ELSE true END as dumpacl "
+						  "FROM pg_type t "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (t.oid = pip.objoid AND pip.classoid = "
+					"(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery);
+	}
+	else if (fout->remoteVersion >= 90200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
 						  "typnamespace, typacl, "
@@ -3629,7 +3677,8 @@ getTypes(Archive *fout, int *numTypes)
 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 						  "typtype, typisdefined, "
 						  "typname[0] = '_' AND typelem != 0 AND "
-						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
+						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray, "
+						  "true as dumpacl "
 						  "FROM pg_type",
 						  username_subquery);
 	}
@@ -3644,7 +3693,8 @@ getTypes(Archive *fout, int *numTypes)
 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 						  "typtype, typisdefined, "
 						  "typname[0] = '_' AND typelem != 0 AND "
-						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
+						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray, "
+						  "true as dumpacl "
 						  "FROM pg_type",
 						  username_subquery);
 	}
@@ -3658,7 +3708,8 @@ getTypes(Archive *fout, int *numTypes)
 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 						  "typtype, typisdefined, "
-						  "typname[0] = '_' AND typelem != 0 AS isarray "
+						  "typname[0] = '_' AND typelem != 0 AS isarray, "
+						  "true as dumpacl "
 						  "FROM pg_type",
 						  username_subquery);
 	}
@@ -3672,7 +3723,8 @@ getTypes(Archive *fout, int *numTypes)
 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 						  "typtype, typisdefined, "
-						  "typname[0] = '_' AND typelem != 0 AS isarray "
+						  "typname[0] = '_' AND typelem != 0 AS isarray, "
+						  "true as dumpacl "
 						  "FROM pg_type",
 						  username_subquery);
 	}
@@ -3688,7 +3740,8 @@ getTypes(Archive *fout, int *numTypes)
 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 						  "typtype, typisdefined, "
-						  "typname[0] = '_' AND typelem != 0 AS isarray "
+						  "typname[0] = '_' AND typelem != 0 AS isarray, "
+						  "true as dumpacl "
 						  "FROM pg_type",
 						  username_subquery);
 	}
@@ -3713,6 +3766,7 @@ getTypes(Archive *fout, int *numTypes)
 	i_typtype = PQfnumber(res, "typtype");
 	i_typisdefined = PQfnumber(res, "typisdefined");
 	i_isarray = PQfnumber(res, "isarray");
+	i_dumpacl = PQfnumber(res, "dumpacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -3746,6 +3800,10 @@ getTypes(Archive *fout, int *numTypes)
 		/* Decide whether we want to dump it */
 		selectDumpableType(&tyinfo[i], dopt);
 
+		/* Decide if we are dumping the ACL for this table or not */
+		if (strcmp(PQgetvalue(res, i, i_dumpacl), "f") == 0)
+			tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		/*
 		 * If it's a domain, fetch info about its constraints, if any
 		 */
@@ -4333,11 +4391,37 @@ getAggregates(Archive *fout, int *numAggs)
 	selectSourceSchema(fout, "pg_catalog");
 
 	/*
-	 * Find all user-defined aggregates.  See comment in getFuncs() for the
+	 * Find all interesting aggregates.  See comment in getFuncs() for the
 	 * rationale behind the filtering logic.
 	 */
-
-	if (fout->remoteVersion >= 80200)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
+						  "pronamespace AS aggnamespace, "
+						  "pronargs, proargtypes, "
+						  "(%s proowner) AS rolname, "
+						  "proacl AS aggacl "
+						  "FROM pg_proc p "
+						  "WHERE proisagg AND ("
+						  "pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl <> pip.initprivs)",
+						  username_subquery);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
+	}
+	else if (fout->remoteVersion >= 80200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
 						  "pronamespace AS aggnamespace, "
@@ -4493,12 +4577,13 @@ getFuncs(Archive *fout, int *numFuncs)
 	selectSourceSchema(fout, "pg_catalog");
 
 	/*
-	 * Find all user-defined functions.  Normally we can exclude functions in
-	 * pg_catalog, which is worth doing since there are several thousand of
-	 * 'em.  However, there are some extensions that create functions in
-	 * pg_catalog.  In normal dumps we can still ignore those --- but in
-	 * binary-upgrade mode, we must dump the member objects of the extension,
-	 * so be sure to fetch any such functions.
+	 * Find all interesting functions.  We include functions in pg_catalog, if
+	 * they have an ACL different from what we set at initdb time (which is
+	 * saved in pg_init_privs for us to perform this check).  There may also be
+	 * functions which are members of extensions which we must dump if we are
+	 * in binary upgrade mode (we'll mark those functions as to-be-dumped when
+	 * we check if the extension is to-be-dumped and we're in binary upgrade
+	 * mode).
 	 *
 	 * Also, in 9.2 and up, exclude functions that are internally dependent on
 	 * something else, since presumably those will be created as a result of
@@ -4507,8 +4592,37 @@ getFuncs(Archive *fout, int *numFuncs)
 	 * because the constructors don't have any dependencies the range type
 	 * doesn't have; otherwise we might not get creation ordering correct.
 	 */
-
-	if (fout->remoteVersion >= 70300)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query,
+						  "SELECT tableoid, oid, proname, prolang, "
+						  "pronargs, proargtypes, prorettype, proacl, "
+						  "pronamespace, "
+						  "(%s proowner) AS rolname "
+						  "FROM pg_proc p "
+						  "WHERE NOT proisagg "
+						  "AND NOT EXISTS (SELECT 1 FROM pg_depend "
+						  "WHERE classid = 'pg_proc'::regclass AND "
+						  "objid = p.oid AND deptype = 'i') AND ("
+						  "pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl <> pip.initprivs)",
+						  username_subquery);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+								 "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
+	}
+	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query,
 						  "SELECT tableoid, oid, proname, prolang, "
@@ -4627,7 +4741,7 @@ getFuncs(Archive *fout, int *numFuncs)
 
 /*
  * getTables
- *	  read all the user-defined tables (no indexes, no catalogs)
+ *	  read all the tables (no indexes)
  * in the system catalogs return them in the TableInfo* structure
  *
  * numTables is set to the number of tables read in
@@ -4671,6 +4785,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_toastreloptions;
 	int			i_reloftype;
 	int			i_relpages;
+	int			i_dumpacl;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
@@ -4700,6 +4815,9 @@ getTables(Archive *fout, int *numTables)
 		/*
 		 * Left join to pick up dependency info linking sequences to their
 		 * owning column, if any (note this dependency is AUTO as of 8.2)
+		 *
+		 * Left join to detect if any privileges are still as-set-at-init,
+		 * in which case we won't dump out ACL commands for those.
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
@@ -4720,7 +4838,62 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+				"CASE WHEN pip.initprivs IS NOT DISTINCT FROM c.relacl AND "
+						  "NOT EXISTS (SELECT * FROM "
+						  "pg_attribute pa LEFT JOIN pg_init_privs colpip ON "
+						  "(pa.attrelid = colpip.objoid AND colpip.classoid = "
+						"(SELECT oid FROM pg_class WHERE relname = 'pg_class') "
+						  "AND pa.attnum = colpip.objsubid) "
+						  "WHERE pa.attrelid = c.oid AND "
+						  "pa.attacl IS DISTINCT FROM colpip.initprivs) "
+						  "THEN false ELSE true END as dumpacl "
+						  "FROM pg_class c "
+						  "LEFT JOIN pg_depend d ON "
+						  "(c.relkind = '%c' AND "
+						  "d.classid = c.tableoid AND d.objid = c.oid AND "
+						  "d.objsubid = 0 AND "
+						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
+					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(c.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_class') AND pip.objsubid = 0) "
+				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
+						  "ORDER BY c.oid",
+						  username_subquery,
+						  RELKIND_SEQUENCE,
+						  RELKIND_RELATION, RELKIND_SEQUENCE,
+						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
+	}
+	else if (fout->remoteVersion >= 90500)
+	{
+		/*
+		 * Left join to pick up dependency info linking sequences to their
+		 * owning column, if any (note this dependency is AUTO as of 8.2)
+		 */
+		appendPQExpBuffer(query,
+						  "SELECT c.tableoid, c.oid, c.relname, "
+						  "c.relacl, c.relkind, c.relnamespace, "
+						  "(%s c.relowner) AS rolname, "
+						  "c.relchecks, c.relhastriggers, "
+						  "c.relhasindex, c.relhasrules, c.relhasoids, "
+						  "c.relrowsecurity, c.relforcerowsecurity, "
+						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
+						  "tc.relfrozenxid AS tfrozenxid, "
+						  "tc.relminmxid AS tminmxid, "
+						  "c.relpersistence, c.relispopulated, "
+						  "c.relreplident, c.relpages, "
+						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+						  "d.refobjid AS owning_tab, "
+						  "d.refobjsubid AS owning_col, "
+						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
+						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
+						  "tc.reloptions AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -4762,7 +4935,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -4804,7 +4978,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -4844,7 +5019,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -4884,7 +5060,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -4923,7 +5100,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -4962,7 +5140,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5001,7 +5180,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5039,7 +5219,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5073,7 +5254,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5102,7 +5284,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5141,7 +5324,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "true as dumpacl "
 						  "FROM pg_class c "
 						  "WHERE relkind IN ('%c', '%c') "
 						  "ORDER BY oid",
@@ -5197,6 +5381,7 @@ getTables(Archive *fout, int *numTables)
 	i_checkoption = PQfnumber(res, "checkoption");
 	i_toastreloptions = PQfnumber(res, "toast_reloptions");
 	i_reloftype = PQfnumber(res, "reloftype");
+	i_dumpacl = PQfnumber(res, "dumpacl");
 
 	if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
 	{
@@ -5275,6 +5460,10 @@ getTables(Archive *fout, int *numTables)
 		else
 			selectDumpableTable(&tblinfo[i], dopt);
 
+		/* Decide if we are dumping the ACL for this table or not */
+		if (strcmp(PQgetvalue(res, i, i_dumpacl), "f") == 0)
+			tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
@@ -6466,17 +6655,37 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	int			i_lanvalidator;
 	int			i_lanacl;
 	int			i_lanowner;
+	int			i_dumpacl;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90000)
+	if (fout->remoteVersion >= 90600)
+	{
+		/* pg_language has a laninline column */
+		appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
+						  "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
+						  "l.laninline, l.lanvalidator, l.lanacl, "
+						  "(%s l.lanowner) AS lanowner, "
+					  "CASE WHEN pip.initprivs IS NOT DISTINCT FROM l.lanacl "
+						  "THEN false ELSE true END as dumpacl "
+						  "FROM pg_language l "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (l.oid = pip.objoid AND pip.classoid = "
+					"(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE l.lanispl "
+						  "ORDER BY l.oid",
+						  username_subquery);
+	}
+	else if (fout->remoteVersion >= 90000)
 	{
 		/* pg_language has a laninline column */
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "laninline, lanvalidator, lanacl, "
-						  "(%s lanowner) AS lanowner "
+						  "(%s lanowner) AS lanowner, "
+						  "true as dumpacl "
 						  "FROM pg_language "
 						  "WHERE lanispl "
 						  "ORDER BY oid",
@@ -6488,7 +6697,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
-						  "(%s lanowner) AS lanowner "
+						  "(%s lanowner) AS lanowner, "
+						  "true as dumpacl "
 						  "FROM pg_language "
 						  "WHERE lanispl "
 						  "ORDER BY oid",
@@ -6500,7 +6710,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
-						  "(%s '10') AS lanowner "
+						  "(%s '10') AS lanowner, "
+						  "true as dumpacl "
 						  "FROM pg_language "
 						  "WHERE lanispl "
 						  "ORDER BY oid",
@@ -6512,7 +6723,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
-						  "(%s '1') AS lanowner "
+						  "(%s '1') AS lanowner, "
+						  "true as dumpacl "
 						  "FROM pg_language "
 						  "WHERE lanispl "
 						  "ORDER BY oid",
@@ -6524,7 +6736,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
-						  "NULL AS lanowner "
+						  "NULL AS lanowner, "
+						  "true as dumpacl "
 						  "FROM pg_language "
 						  "WHERE lanispl "
 						  "ORDER BY oid");
@@ -6534,7 +6747,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
-						  "NULL AS lanowner "
+						  "NULL AS lanowner, "
+						  "true as dumpacl "
 						  "FROM pg_language "
 						  "WHERE lanispl "
 						  "ORDER BY oid");
@@ -6546,7 +6760,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 						  "oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
-						  "NULL AS lanowner "
+						  "NULL AS lanowner, "
+						  "true as dumpacl "
 						  "FROM pg_language "
 						  "WHERE lanispl "
 						  "ORDER BY oid");
@@ -6569,6 +6784,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	i_lanvalidator = PQfnumber(res, "lanvalidator");
 	i_lanacl = PQfnumber(res, "lanacl");
 	i_lanowner = PQfnumber(res, "lanowner");
+	i_dumpacl = PQfnumber(res, "dumpacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -6588,6 +6804,10 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		/* Decide whether we want to dump it */
 		selectDumpableProcLang(&(planginfo[i]), dopt);
 
+		/* Decide if we are dumping the ACL for this table or not */
+		if (strcmp(PQgetvalue(res, i, i_dumpacl), "f") == 0)
+			planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion < 70300)
 		{
 			/*
@@ -7797,6 +8017,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	int			i_fdwvalidator;
 	int			i_fdwacl;
 	int			i_fdwoptions;
+	int			i_dumpacl;
 
 	/* Before 8.4, there are no foreign-data wrappers */
 	if (fout->remoteVersion < 80400)
@@ -7810,7 +8031,28 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90100)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
+						  "(%s f.fdwowner) AS rolname, "
+						  "f.fdwhandler::pg_catalog.regproc, "
+						  "f.fdwvalidator::pg_catalog.regproc, f.fdwacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.fdwoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS fdwoptions, "
+					  "CASE WHEN pip.initprivs IS NOT DISTINCT FROM f.fdwacl "
+						  "THEN false ELSE true END as dumpacl "
+						  "FROM pg_foreign_data_wrapper f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+		"(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_data_wrapper') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery);
+	}
+	else if (fout->remoteVersion >= 90100)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
 						  "(%s fdwowner) AS rolname, "
@@ -7821,7 +8063,8 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 						  "quote_literal(option_value) "
 						  "FROM pg_options_to_table(fdwoptions) "
 						  "ORDER BY option_name"
-						  "), E',\n    ') AS fdwoptions "
+						  "), E',\n    ') AS fdwoptions, "
+						  "true as dumpacl "
 						  "FROM pg_foreign_data_wrapper",
 						  username_subquery);
 	}
@@ -7836,7 +8079,8 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 						  "quote_literal(option_value) "
 						  "FROM pg_options_to_table(fdwoptions) "
 						  "ORDER BY option_name"
-						  "), E',\n    ') AS fdwoptions "
+						  "), E',\n    ') AS fdwoptions, "
+						  "true as dumpacl "
 						  "FROM pg_foreign_data_wrapper",
 						  username_subquery);
 	}
@@ -7856,6 +8100,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	i_fdwvalidator = PQfnumber(res, "fdwvalidator");
 	i_fdwacl = PQfnumber(res, "fdwacl");
 	i_fdwoptions = PQfnumber(res, "fdwoptions");
+	i_dumpacl = PQfnumber(res, "dumpacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -7873,6 +8118,10 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(fdwinfo[i].dobj), dopt);
+
+		/* Decide if we are dumping the ACL for this table or not */
+		if (strcmp(PQgetvalue(res, i, i_dumpacl), "f") == 0)
+			fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -7907,6 +8156,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	int			i_srvversion;
 	int			i_srvacl;
 	int			i_srvoptions;
+	int			i_dumpacl;
 
 	/* Before 8.4, there are no foreign servers */
 	if (fout->remoteVersion < 80400)
@@ -7920,17 +8170,41 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
-					  "(%s srvowner) AS rolname, "
-					  "srvfdw, srvtype, srvversion, srvacl,"
-					  "array_to_string(ARRAY("
-					  "SELECT quote_ident(option_name) || ' ' || "
-					  "quote_literal(option_value) "
-					  "FROM pg_options_to_table(srvoptions) "
-					  "ORDER BY option_name"
-					  "), E',\n    ') AS srvoptions "
-					  "FROM pg_foreign_server",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
+						  "(%s f.srvowner) AS rolname, "
+						  "f.srvfdw, f.srvtype, f.srvversion, f.srvacl,"
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions, "
+					  "CASE WHEN pip.initprivs IS NOT DISTINCT FROM f.srvacl "
+						  "THEN false ELSE true END as dumpacl "
+						  "FROM pg_foreign_server f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+		"(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_server') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery);
+	}
+	else
+	{
+		appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
+						  "(%s srvowner) AS rolname, "
+						  "srvfdw, srvtype, srvversion, srvacl,"
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions, "
+						  "true as dumpacl "
+						  "FROM pg_foreign_server",
+						  username_subquery);
+	}
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -7948,6 +8222,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	i_srvversion = PQfnumber(res, "srvversion");
 	i_srvacl = PQfnumber(res, "srvacl");
 	i_srvoptions = PQfnumber(res, "srvoptions");
+	i_dumpacl = PQfnumber(res, "dumpacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -7966,6 +8241,10 @@ getForeignServers(Archive *fout, int *numForeignServers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(srvinfo[i].dobj), dopt);
+
+		/* Decide if we are dumping the ACL for this or not */
+		if (strcmp(PQgetvalue(res, i, i_dumpacl), "f") == 0)
+			srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
-- 
2.5.0


From 64083a27286737e9e04a268a790b64c0365cbdc3 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 14 Mar 2016 11:05:25 -0400
Subject: [PATCH 5/5] Use GRANT system to manage access to sensitive functions

Now that pg_dump will properly dump out any ACL changes made to
functions which exist in pg_catalog, switch to using the GRANT system
to manage access to those functions.

This means removing 'if (!superuser()) ereport()' checks from the
functions themselves and then REVOKEing EXECUTE right from 'public' for
these functions in system_views.sql.
---
 src/backend/access/transam/xlogfuncs.c | 48 +++++++++++++---------------------
 src/backend/catalog/system_views.sql   | 15 +++++++++++
 src/backend/utils/adt/misc.c           | 16 +++++-------
 3 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 31cbb01..1c1bffd 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -43,6 +43,9 @@
  * contains the user-supplied label string (typically this would be used
  * to tell where the backup dump will be stored) and the starting time and
  * starting WAL location for the dump.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_start_backup(PG_FUNCTION_ARGS)
@@ -55,11 +58,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
 
 	backupidstr = text_to_cstring(backupid);
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		   errmsg("must be superuser or replication role to run a backup")));
-
 	/* Make sure we can open the directory with tablespaces in it */
 	dir = AllocateDir("pg_tblspc");
 	if (!dir)
@@ -86,17 +84,15 @@ pg_start_backup(PG_FUNCTION_ARGS)
  * record for that and the file is for informational and debug purposes only.
  *
  * Note: different from CancelBackup which just cancels online backup mode.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_stop_backup(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	stoppoint;
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		 (errmsg("must be superuser or replication role to run a backup"))));
-
 	stoppoint = do_pg_stop_backup(NULL, true, NULL);
 
 	PG_RETURN_LSN(stoppoint);
@@ -104,17 +100,15 @@ pg_stop_backup(PG_FUNCTION_ARGS)
 
 /*
  * pg_switch_xlog: switch to next xlog file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_switch_xlog(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	switchpoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-			 (errmsg("must be superuser to switch transaction log files"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -131,6 +125,9 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
 
 /*
  * pg_create_restore_point: a named point for restore
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_create_restore_point(PG_FUNCTION_ARGS)
@@ -139,11 +136,6 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
 	char	   *restore_name_str;
 	XLogRecPtr	restorepoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to create a restore point"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -365,15 +357,13 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_pause - pause recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -387,15 +377,13 @@ pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_resume - resume recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_resume(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 84aa061..69a2dd2 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -972,3 +972,18 @@ RETURNS jsonb
 LANGUAGE INTERNAL
 STRICT IMMUTABLE
 AS 'jsonb_set';
+
+-- The default permissions for functions mean that anyone can execute them.
+-- A number of functions shouldn't be executable by just anyone, but rather
+-- than use explicit 'superuser()' checks in those functions, we use the GRANT
+-- system to REVOKE access to those functions at initdb time.  Administrators
+-- can later change who can access these functions, or leave them as only
+-- available to superuser / cluster owner, if they choose.
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_switch_xlog() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_pause() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_resume() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_rotate_logfile() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 43f36db..02d9ba3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -320,15 +320,13 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
 
 /*
  * Signal to reload the database configuration
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_reload_conf(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to signal the postmaster"))));
-
 	if (kill(PostmasterPid, SIGHUP))
 	{
 		ereport(WARNING,
@@ -342,15 +340,13 @@ pg_reload_conf(PG_FUNCTION_ARGS)
 
 /*
  * Rotate log file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_rotate_logfile(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to rotate log files"))));
-
 	if (!Logging_collector)
 	{
 		ereport(WARNING,
-- 
2.5.0

#2Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Stephen Frost (#1)

Hi, Stephen!

I'm signed to review this patch. At first, patch wasn't applied cleanly, it
had a conflict at the end of system_views.sql. But that way very easy to
fix.

On Mon, Mar 14, 2016 at 7:00 PM, Stephen Frost <sfrost@snowman.net> wrote:

I've not included it in this patch, but my thinking here would be to add
a check to the GRANT functions which checks 'if (creating_extension)'
and records/updates the entries in pg_init_privs for those objects.
This is similar to how we handle dependencies for extensions currently.
That way, extensions don't have to do anything and if the user changes
the permissions on an extension's object, the permissions for that
object would then be dumped out.

This still requires more testing, documentation, and I'll see about
making it work completely for extensions also, but wanted to provide an
update and solicit for review/comments.

The patches have been broken up in what I hope is a logical way for
those who wish to review/comment:

#1 - Add the pg_init_privs catalog
#2 - Change pg_dump to use a bitmap instead of boolean for 'dump'
#3 - Split 'dump' into 'dump' and 'dump_contains'
#4 - Make pg_dump include changed ACLs in dump of 'pg_catalog'

+  "CASE WHEN pip.initprivs IS NOT DISTINCT FROM n.nspacl "
+  "THEN false ELSE true END as dumpacl "

Why don't just write " pip.initprivs IS DISTINCT FROM n.nspacl AS dumpacl"?
I think there are few places whene CASE could be eliminated.

+ appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
+  "pronamespace AS aggnamespace, "
+  "pronargs, proargtypes, "
+  "(%s proowner) AS rolname, "
+  "proacl AS aggacl "
+  "FROM pg_proc p "
+  "WHERE proisagg AND ("
+  "pronamespace != "
+  "(SELECT oid FROM pg_namespace "
+  "WHERE nspname = 'pg_catalog') OR "
+  "EXISTS (SELECT * FROM pg_init_privs pip "
+  "WHERE p.oid = pip.objoid AND pip.classoid = "
+  "(SELECT oid FROM pg_class "
+  "WHERE relname = 'pg_proc') "
+  "AND p.proacl <> pip.initprivs)",
+  username_subquery);

Why do we compare ACLs using <> funcs and using IS DISTINCT for other
objects? Is it intentional? Assuming most of proacl values are NULLs when
you change it, acl wouldn't be dumped since NULL <> value IS NULL.

In general, these checks using subqueries looks complicated for me, hard to
validate and needs a lot of testing. Could we implement function "bool
need_acl_dump(oid objoid, oid classoid, int objsubid, proacl acl)" and call
it?

#5 - Remove 'if (!superuser()) ereport()' calls and REVOKE EXECUTE

Other things in the patches looks good for me except they need tests and
documentation.
I'm marking this waiting for author.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#3Stephen Frost
sfrost@snowman.net
In reply to: Alexander Korotkov (#2)
1 attachment(s)

Alexander,

* Alexander Korotkov (a.korotkov@postgrespro.ru) wrote:

I'm signed to review this patch. At first, patch wasn't applied cleanly, it
had a conflict at the end of system_views.sql. But that way very easy to
fix.

Fantastic! Many thanks!

On Mon, Mar 14, 2016 at 7:00 PM, Stephen Frost <sfrost@snowman.net> wrote:

I've not included it in this patch, but my thinking here would be to add
a check to the GRANT functions which checks 'if (creating_extension)'
and records/updates the entries in pg_init_privs for those objects.
This is similar to how we handle dependencies for extensions currently.
That way, extensions don't have to do anything and if the user changes
the permissions on an extension's object, the permissions for that
object would then be dumped out.

This still requires more testing, documentation, and I'll see about
making it work completely for extensions also, but wanted to provide an
update and solicit for review/comments.

The patches have been broken up in what I hope is a logical way for
those who wish to review/comment:

#1 - Add the pg_init_privs catalog
#2 - Change pg_dump to use a bitmap instead of boolean for 'dump'
#3 - Split 'dump' into 'dump' and 'dump_contains'
#4 - Make pg_dump include changed ACLs in dump of 'pg_catalog'

+  "CASE WHEN pip.initprivs IS NOT DISTINCT FROM n.nspacl "
+  "THEN false ELSE true END as dumpacl "

Why don't just write " pip.initprivs IS DISTINCT FROM n.nspacl AS dumpacl"?
I think there are few places whene CASE could be eliminated.

Unfortunately, the reality is quite the opposite, as I expect you'll see
from the latest version of this patch. Apologies for not posting a
newer patch sooner, but I've continued to work on it since my last post.

In particular, I've now added support for handling initial privileges of
extensions and dealt with both the addition of privileges but also the
revocation of the inital ones the object had. I also had to make
adjustments for dealing with binary-upgrade mode with extensions.

The attached also properly splits out the ACL arrays into individual
items for consideration, so that we don't end up in odd cases where
there appears to be a difference due to a change in the ordering
(perhaps someone revoked a privilege which existed initially, only to
add it back identically later, but which would put it at the end of the
array).

+ appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
+  "pronamespace AS aggnamespace, "
+  "pronargs, proargtypes, "
+  "(%s proowner) AS rolname, "
+  "proacl AS aggacl "
+  "FROM pg_proc p "
+  "WHERE proisagg AND ("
+  "pronamespace != "
+  "(SELECT oid FROM pg_namespace "
+  "WHERE nspname = 'pg_catalog') OR "
+  "EXISTS (SELECT * FROM pg_init_privs pip "
+  "WHERE p.oid = pip.objoid AND pip.classoid = "
+  "(SELECT oid FROM pg_class "
+  "WHERE relname = 'pg_proc') "
+  "AND p.proacl <> pip.initprivs)",
+  username_subquery);

Why do we compare ACLs using <> funcs and using IS DISTINCT for other
objects? Is it intentional? Assuming most of proacl values are NULLs when
you change it, acl wouldn't be dumped since NULL <> value IS NULL.

That wasn't intentional and was caught a couple days ago while I was
reviewing the patch and working through adding extension support, many
thanks for taking a look through the patch and pointing it out though,
definitely a good catch.

In general, these checks using subqueries looks complicated for me, hard to
validate and needs a lot of testing. Could we implement function "bool
need_acl_dump(oid objoid, oid classoid, int objsubid, proacl acl)" and call
it?

We're in pg_dump here, which could be working against different major
versions of PG, so I'd rather avoid doing that. Also, I've added a ton
of comments across the patch which hopefully help explain what's going
on, along with some of the documentation which will be necessary (though
there's more to do on that front, in particular when it comes to
pg_dump).

#5 - Remove 'if (!superuser()) ereport()' calls and REVOKE EXECUTE

Other things in the patches looks good for me except they need tests and
documentation.
I'm marking this waiting for author.

I'd argue that the biggest piece that needs better testing is pg_dump,
but we don't have a very good framework for testing it currently during
the regression tests. We do run pg_upgrade and that includes dumping
out the regression database, which is good, and that all passes
currently, and I've tested that doing a pg_dump against all versions
of PG which I could compile easily on my Ubuntu 15.10 laptop (7.4 and
above) of their regression databases at least doesn't fail and a bit of
checking by hand leads me to believe that they look reasonable.

I've also made changes to the initdb'd ACLs (granting and revoking them)
and gotten the expected results from pg_dump, and played around a bit
with doing the same for an extension (pg_buffercache, if you're
curious) and that appeared to all work.

Attached is a new version to look at and play with. I'm not entirely
thrilled with some of the hacking that was necessary to make
buildACLCommands not throw in extra (and now unnecessary) commands and
that deserves more comments (and I'm a bit suspicious that there's
actually an unintentional bug which actually ends up doing the right
thing, but not for the right reasons, when it comes to how the 'owner'
case is handled...). There's also more to be said when it comes to the
use of acldefault(), I expect, though I was having some serious
difficulty coming up with a better answer (suggestions welcome...).

In any case, it's awful late, but wanted to show where I'm currently at
with all of this, so my apologies in advance for any grossly incorrect
statements, comments, or code. I look forward to comments and will
attempt to address them tomorrow night, otherwise I'll probably be back
looking this over again myself.

The complications of this approach are, impressively, worse than I had
expected them to be, and I thought they'd be pretty bad.

Thanks!

Stephen

Attachments:

catalog_acls_v4.patchtext/x-diff; charset=us-asciiDownload
From 38e2efd576e818dd850f70bc21321641e523d958 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Thu, 10 Mar 2016 20:56:09 -0500
Subject: [PATCH 1/5] Add new catalog called pg_init_privs

This new catalog holds the privileges which the system was
initialized with at initdb time, along with any permissions set
by extensions at CREATE EXTENSION time.  This allows pg_dump
(and any other similar use-cases) to detect when the privileges
set on initdb-created or extension-created objects have been
changed from what they were set to at initdb/extension-creation
time and handle those changes appropriately.
---
 doc/src/sgml/catalogs.sgml                 |  97 +++++++++++++++++++
 src/backend/catalog/Makefile               |   2 +-
 src/backend/catalog/aclchk.c               | 121 ++++++++++++++++++++++++
 src/backend/catalog/dependency.c           |  46 +++++++++-
 src/bin/initdb/initdb.c                    | 143 +++++++++++++++++++++++++++++
 src/include/catalog/indexing.h             |   3 +
 src/include/catalog/pg_init_privs.h        | 100 ++++++++++++++++++++
 src/test/regress/expected/sanity_check.out |   1 +
 8 files changed, 509 insertions(+), 4 deletions(-)
 create mode 100644 src/include/catalog/pg_init_privs.h

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 951f59b..ffec79b 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -179,6 +179,11 @@
      </row>
 
      <row>
+      <entry><link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link></entry>
+      <entry>object initial privileges</entry>
+     </row>
+
+     <row>
       <entry><link linkend="catalog-pg-language"><structname>pg_language</structname></link></entry>
       <entry>languages for writing functions</entry>
      </row>
@@ -3748,6 +3753,98 @@
 
  </sect1>
 
+ <sect1 id="catalog-pg-init-privs">
+  <title><structname>pg_init_privs</structname></title>
+
+  <indexterm zone="catalog-pg-init-privs">
+   <primary>pg_init_privs</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_init_privs</> records information about
+   the initial privileges of objects in the system.  There is one entry
+   for each object in the database which has a non-default (non-NULL)
+   initial set of privileges.
+  </para>
+
+  <para>
+   Objects can have initial privileges either by having those privileges set
+   when the system is initialized (by initdb) or when the object is created
+   during a CREATE EXTENSION and the extension creation script sets initial
+   privileges using the GRANT system.  Note that the system will automatically
+   handle recording of the privileges during the CREATE EXTENSION script and
+   that extension authors need only use the GRANT command in their script.
+   The privtype column indicates if the initial privilege was set at initdb
+   time or at CREATE EXTENSION time.
+  </para>
+
+  <table>
+   <title><structname>pg_inherits</> Columns</title>
+
+   <tgroup cols="4">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>objoid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry>any OID column</entry>
+      <entry>The OID of the specific object</entry>
+     </row>
+
+     <row>
+      <entry><structfield>classoid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
+      <entry>The OID of the system catalog the object is in</entry>
+     </row>
+
+     <row>
+      <entry><structfield>objsubid</structfield></entry>
+      <entry><type>int4</type></entry>
+      <entry></entry>
+      <entry>
+       For a table column, this is the column number (the
+       <structfield>objoid</> and <structfield>classoid</> refer to the
+       table itself).  For all other object types, this column is
+       zero.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>privtype</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>
+       A code defining the type of initial privilege of this object; see text
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>initprivs</structfield></entry>
+      <entry><type>aclitem[]</type></entry>
+      <entry></entry>
+      <entry>
+       The initial access privileges; see
+       <xref linkend="sql-grant"> and
+       <xref linkend="sql-revoke">
+       for details
+      </entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
 
  <sect1 id="catalog-pg-language">
   <title><structname>pg_language</structname></title>
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 25130ec..1ce7610 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -40,7 +40,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_ts_parser.h pg_ts_template.h pg_extension.h \
 	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
 	pg_foreign_table.h pg_policy.h pg_replication_origin.h \
-	pg_default_acl.h pg_seclabel.h pg_shseclabel.h \
+	pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
 	pg_collation.h pg_range.h pg_transform.h \
 	toasting.h indexing.h \
     )
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 0f3bc07..5e70960 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_extension.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
+#include "catalog/pg_init_privs.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_largeobject_metadata.h"
@@ -49,6 +50,7 @@
 #include "catalog/pg_ts_dict.h"
 #include "commands/dbcommands.h"
 #include "commands/event_trigger.h"
+#include "commands/extension.h"
 #include "commands/proclang.h"
 #include "commands/tablespace.h"
 #include "foreign/foreign.h"
@@ -119,6 +121,8 @@ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
 						 AttrNumber att_number, const char *colname);
 static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
 		   Oid roleid, AclMode mask, AclMaskHow how);
+static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
+									Acl *new_acl);
 
 
 #ifdef ACLDEBUG
@@ -1678,6 +1682,9 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(attRelation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(relOid, RelationRelationId, attnum, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(RelationRelationId, relOid, attnum,
 							  ownerId,
@@ -1939,6 +1946,9 @@ ExecGrant_Relation(InternalGrant *istmt)
 			/* keep the catalog indexes up to date */
 			CatalogUpdateIndexes(relation, newtuple);
 
+			/* Update initial privileges for extensions */
+			recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
+
 			/* Update the shared dependency ACL info */
 			updateAclDependencies(RelationRelationId, relOid, 0,
 								  ownerId,
@@ -2254,6 +2264,10 @@ ExecGrant_Fdw(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
+								new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ForeignDataWrapperRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2379,6 +2393,9 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ForeignServerRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2503,6 +2520,9 @@ ExecGrant_Function(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ProcedureRelationId, funcId, 0,
 							  ownerId,
@@ -2633,6 +2653,9 @@ ExecGrant_Language(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
 							  ownerId,
@@ -2772,6 +2795,9 @@ ExecGrant_Largeobject(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(LargeObjectRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2897,6 +2923,9 @@ ExecGrant_Namespace(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
 							  ownerId,
@@ -3158,6 +3187,9 @@ ExecGrant_Type(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(TypeRelationId, typId, 0,
 							  ownerId,
@@ -5174,3 +5206,92 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
 
 	return result;
 }
+
+/*
+ * record initial ACL for extension objects
+ */
+static void
+recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
+{
+	Relation	relation;
+	ScanKeyData key[3];
+	SysScanDesc scan;
+	HeapTuple	tuple;
+	HeapTuple	oldtuple;
+
+	if (!creating_extension)
+		return;
+
+	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_init_privs_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(objoid));
+	ScanKeyInit(&key[1],
+				Anum_pg_init_privs_classoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(classoid));
+	ScanKeyInit(&key[2],
+				Anum_pg_init_privs_objsubid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(objsubid));
+
+	scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
+							  NULL, 3, key);
+
+	/* There should exist only one entry or none. */
+	oldtuple = systable_getnext(scan);
+
+	systable_endscan(scan);
+
+	/* If we find an entry, update it with the latest ACL. */
+	if (HeapTupleIsValid(oldtuple))
+	{
+		Datum		values[Natts_pg_init_privs];
+		bool		nulls[Natts_pg_init_privs];
+		bool		replace[Natts_pg_init_privs];
+
+		MemSet(values, 0, sizeof(values));
+		MemSet(nulls, false, sizeof(nulls));
+		MemSet(replace, false, sizeof(replace));
+
+		values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
+		replace[Anum_pg_init_privs_privs - 1] = true;
+
+		oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
+									 values, nulls, replace);
+
+		simple_heap_update(relation, &oldtuple->t_self, oldtuple);
+
+		/* keep the catalog indexes up to date */
+		CatalogUpdateIndexes(relation, oldtuple);
+	}
+	else
+	{
+		/* No entry found, so add it. */
+		Datum		values[Natts_pg_init_privs];
+		bool		nulls[Natts_pg_init_privs];
+
+		MemSet(nulls, false, sizeof(nulls));
+
+		values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
+		values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
+		values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
+		values[Anum_pg_init_privs_privtype - 1] =
+			CharGetDatum(INITPRIVS_EXTENSION);
+		values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
+
+		tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
+
+		simple_heap_insert(relation, tuple);
+
+		/* keep the catalog indexes up to date */
+		CatalogUpdateIndexes(relation, tuple);
+	}
+
+	/* prevent error when processing objects multiple times */
+	CommandCounterIncrement();
+
+	heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index c48e37b..3db440b 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -38,6 +38,7 @@
 #include "catalog/pg_extension.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
+#include "catalog/pg_init_privs.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_namespace.h"
@@ -194,6 +195,7 @@ static bool object_address_present_add_flags(const ObjectAddress *object,
 static bool stack_address_present_add_flags(const ObjectAddress *object,
 								int flags,
 								ObjectAddressStack *stack);
+static void DeleteInitPrivs(const ObjectAddress *object);
 
 
 /*
@@ -1102,12 +1104,13 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
 
 
 	/*
-	 * Delete any comments or security labels associated with this object.
-	 * (This is a convenient place to do these things, rather than having
-	 * every object type know to do it.)
+	 * Delete any comments, security labels, or initial privileges associated
+	 * with this object.  (This is a convenient place to do these things,
+	 * rather than having every object type know to do it.)
 	 */
 	DeleteComments(object->objectId, object->classId, object->objectSubId);
 	DeleteSecurityLabel(object);
+	DeleteInitPrivs(object);
 
 	/*
 	 * CommandCounterIncrement here to ensure that preceding changes are all
@@ -2421,3 +2424,40 @@ getObjectClass(const ObjectAddress *object)
 	elog(ERROR, "unrecognized object class: %u", object->classId);
 	return OCLASS_CLASS;		/* keep compiler quiet */
 }
+
+/*
+ * delete initial ACL for extension objects
+ */
+static void
+DeleteInitPrivs(const ObjectAddress *object)
+{
+	Relation	relation;
+	ScanKeyData key[3];
+	SysScanDesc scan;
+	HeapTuple	oldtuple;
+
+	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_init_privs_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->objectId));
+	ScanKeyInit(&key[1],
+				Anum_pg_init_privs_classoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->classId));
+	ScanKeyInit(&key[2],
+				Anum_pg_init_privs_objsubid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(object->objectSubId));
+
+	scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
+							  NULL, 3, key);
+
+	while (HeapTupleIsValid(oldtuple = systable_getnext(scan)))
+		simple_heap_delete(relation, &oldtuple->t_self);
+
+	systable_endscan(scan);
+
+	heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index ed3ba7b..858667b 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1989,6 +1989,11 @@ setup_dictionary(FILE *cmdfd)
  * Some objects may require different permissions by default, so we
  * make sure we don't overwrite privilege sets that have already been
  * set (NOT NULL).
+ *
+ * Also populate pg_init_privs to save what the privileges are at init
+ * time.  This is used by pg_dump to allow users to change privileges
+ * on catalog objects and to have those privilege changes preserved
+ * across dump/reload and pg_upgrade.
  */
 static void
 setup_privileges(FILE *cmdfd)
@@ -2002,6 +2007,144 @@ setup_privileges(FILE *cmdfd)
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
 		"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        0,"
+		"        relacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_class"
+		"    WHERE"
+		"        relacl IS NOT NULL"
+		"        AND relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        pg_class.oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        pg_attribute.attnum,"
+		"        pg_attribute.attacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_class"
+		"        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
+		"    WHERE"
+		"        pg_attribute.attacl IS NOT NULL"
+		"        AND pg_class.relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),"
+		"        0,"
+		"        proacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_proc"
+		"    WHERE"
+		"        proacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_type'),"
+		"        0,"
+		"        typacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_type"
+		"    WHERE"
+		"        typacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_language'),"
+		"        0,"
+		"        lanacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_language"
+		"    WHERE"
+		"        lanacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_largeobject_metadata'),"
+		"        0,"
+		"        lomacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_largeobject_metadata"
+		"    WHERE"
+		"        lomacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),"
+		"        0,"
+		"        nspacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_namespace"
+		"    WHERE"
+		"        nspacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_database'),"
+		"        0,"
+		"        datacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_database"
+		"    WHERE"
+		"        datacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_tablespace'),"
+		"        0,"
+		"        spcacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_tablespace"
+		"    WHERE"
+		"        spcacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_foreign_data_wrapper'),"
+		"        0,"
+		"        fdwacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_foreign_data_wrapper"
+		"    WHERE"
+		"        fdwacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class "
+		"		  WHERE relname = 'pg_foreign_server'),"
+		"        0,"
+		"        srvacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_foreign_server"
+		"    WHERE"
+		"        srvacl IS NOT NULL;",
 		NULL
 	};
 
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index ab2c1a8..1a94f6d 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -162,6 +162,9 @@ DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using b
 DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhparent oid_ops));
 #define InheritsParentIndexId  2187
 
+DECLARE_UNIQUE_INDEX(pg_init_privs_o_c_o_index, 2740, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
+#define InitPrivsObjIndexId  2740
+
 DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops));
 #define LanguageNameIndexId  2681
 DECLARE_UNIQUE_INDEX(pg_language_oid_index, 2682, on pg_language using btree(oid oid_ops));
diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h
new file mode 100644
index 0000000..feb1d24
--- /dev/null
+++ b/src/include/catalog/pg_init_privs.h
@@ -0,0 +1,100 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_init_privs.h
+ *	  definition of the system "initial privileges" relation (pg_init_privs)
+ *
+ * NOTE: an object is identified by the OID of the row that primarily
+ * defines the object, plus the OID of the table that that row appears in.
+ * For example, a function is identified by the OID of its pg_proc row
+ * plus the pg_class OID of table pg_proc.  This allows unique identification
+ * of objects without assuming that OIDs are unique across tables.
+ *
+ * Since attributes don't have OIDs of their own, we identify an attribute
+ * privilege by the objoid+classoid of its parent table, plus an "objsubid"
+ * giving the attribute column number.  "objsubid" must be zero in a privilege
+ * for a table itself, so that it is distinct from any column privilege.
+ * Currently, objsubid is unused and zero for all other kinds of objects.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_init_privs.h
+ *
+ * NOTES
+ *		the genbki.pl script reads this file and generates .bki
+ *		information from the DATA() statements.
+ *
+ *		XXX do NOT break up DATA() statements into multiple lines!
+ *			the scripts are not as smart as you might think...
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_INIT_PRIVS_H
+#define PG_INIT_PRIVS_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ *		pg_init_privs definition.  cpp turns this into
+ *		typedef struct FormData_pg_init_privs
+ * ----------------
+ */
+#define InitPrivsRelationId  2739
+
+CATALOG(pg_init_privs,2739) BKI_WITHOUT_OIDS
+{
+	Oid			objoid;			/* OID of object itself */
+	Oid			classoid;		/* OID of table containing object */
+	int32		objsubid;		/* column number, or 0 if not used */
+	char		privtype;		/* from initdb or extension? */
+
+#ifdef CATALOG_VARLEN			/* variable-length fields start here */
+	aclitem initprivs[1] BKI_FORCE_NOT_NULL;	/* initial privs on object */
+#endif
+} FormData_pg_init_privs;
+
+/* ----------------
+ *		Form_pg_init_privs corresponds to a pointer to a tuple with
+ *		the format of pg_init_privs relation.
+ * ----------------
+ */
+typedef FormData_pg_init_privs *Form_pg_init_privs;
+
+/* ----------------
+ *		compiler constants for pg_init_privs
+ * ----------------
+ */
+#define Natts_pg_init_privs				5
+#define Anum_pg_init_privs_objoid		1
+#define Anum_pg_init_privs_classoid		2
+#define Anum_pg_init_privs_objsubid		3
+#define Anum_pg_init_privs_privtype		4
+#define Anum_pg_init_privs_privs		5
+
+/*
+ * It is important to know if the initial privileges are from initdb or from an
+ * extension.  This enum is used to provide that differentiation and the two
+ * places which populate this table (initdb and during CREATE EXTENSION, see
+ * recordExtensionInitPriv()) know to use the correct values.
+ */
+
+typedef enum InitPrivsType
+{
+	INITPRIVS_INITDB = 'i',
+	INITPRIVS_EXTENSION = 'e'
+} InitPrivsType;
+
+/* ----------------
+ *		initial contents of pg_init_privs
+ * ----------------
+ */
+
+/*
+ *	Because the contents of this table depend on what is done with the other
+ *	objects in the system (and, in particular, may change due to changes is
+ *	system_views.sql), there is no initialization here.
+ *
+ *	The initial contents are loaded near the end of initdb.
+ */
+
+#endif   /* PG_INIT_PRIVS_H */
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index eb0bc88..1c087a3 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -110,6 +110,7 @@ pg_foreign_server|t
 pg_foreign_table|t
 pg_index|t
 pg_inherits|t
+pg_init_privs|t
 pg_language|t
 pg_largeobject|t
 pg_largeobject_metadata|t
-- 
2.5.0


From fbf969be40b71a5be659e2d96aae15106e54fe06 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:31:03 -0400
Subject: [PATCH 2/5] In pg_dump, use a bitmap to represent what to include

pg_dump has historically used a simple boolean 'dump' value to indicate
if a given object should be included in the dump or not.  Instead, use
a bitmap which breaks down the components of an object into their
distinct pieces and use that bitmap to only include the components
requested.

This does not include any behavioral change, but is in preperation for
the change to dump out just ACLs for objects in pg_catalog.
---
 src/bin/pg_dump/common.c  |    2 +-
 src/bin/pg_dump/pg_dump.c | 1518 ++++++++++++++++++++++++---------------------
 src/bin/pg_dump/pg_dump.h |   14 +-
 3 files changed, 841 insertions(+), 693 deletions(-)

diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index f798b15..507b0bf 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -437,7 +437,7 @@ AssignDumpId(DumpableObject *dobj)
 	dobj->dumpId = ++lastDumpId;
 	dobj->name = NULL;			/* must be set later */
 	dobj->namespace = NULL;		/* may be set later */
-	dobj->dump = true;			/* default assumption */
+	dobj->dump = DUMP_COMPONENT_ALL;	/* default assumption */
 	dobj->ext_member = false;	/* default assumption */
 	dobj->dependencies = NULL;
 	dobj->nDeps = 0;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 64c2673..08a2e93 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1284,7 +1284,7 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
 	 * extension contents with something different.
 	 */
 	if (!dopt->binary_upgrade)
-		dobj->dump = false;
+		dobj->dump = DUMP_COMPONENT_NONE;
 	else
 		dobj->dump = ext->dobj.dump;
 
@@ -1306,16 +1306,18 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 * namespaces. If specific namespaces are being dumped, dump just those
 	 * namespaces. Otherwise, dump all non-system namespaces.
 	 */
+
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
 		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
-												   nsinfo->dobj.catId.oid);
+								   nsinfo->dobj.catId.oid) ?
+							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = true;
+		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
@@ -1323,7 +1325,7 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	if (nsinfo->dobj.dump &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1342,7 +1344,8 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	 */
 	if (table_include_oids.head != NULL)
 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
-												   tbinfo->dobj.catId.oid);
+												   tbinfo->dobj.catId.oid) ?
+								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
 
@@ -1352,7 +1355,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	if (tbinfo->dobj.dump &&
 		simple_oid_list_member(&table_exclude_oids,
 							   tbinfo->dobj.catId.oid))
-		tbinfo->dobj.dump = false;
+		tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1381,7 +1384,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 		if (tytable != NULL)
 			tyinfo->dobj.dump = tytable->dobj.dump;
 		else
-			tyinfo->dobj.dump = false;
+			tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
 		return;
 	}
 
@@ -1401,11 +1404,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	/* dump only types in dumpable namespaces */
-	if (!tyinfo->dobj.namespace->dobj.dump)
-		tyinfo->dobj.dump = false;
-	else
-		tyinfo->dobj.dump = true;
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
 }
 
 /*
@@ -1424,7 +1423,8 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	if (dinfo->dobj.namespace)
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
-		dinfo->dobj.dump = dopt->include_everything;
+		dinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1443,9 +1443,10 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		cast->dobj.dump = false;
+		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		cast->dobj.dump = dopt->include_everything;
+		cast->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1463,9 +1464,10 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		plang->dobj.dump = false;
+		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = dopt->include_everything;
+		plang->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1482,9 +1484,10 @@ static void
 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 {
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = false;
+		extinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		extinfo->dobj.dump = dopt->include_everything;
+		extinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1506,7 +1509,8 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	if (dobj->namespace)
 		dobj->dump = dobj->namespace->dobj.dump;
 	else
-		dobj->dump = dopt->include_everything;
+		dobj->dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1911,13 +1915,14 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
 	 * dependency on its table as "special" and pass it to ArchiveEntry now.
 	 * See comments for BuildArchiveDependencies.
 	 */
-	ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
-				 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
-				 NULL, tbinfo->rolname,
-				 false, "TABLE DATA", SECTION_DATA,
-				 "", "", copyStmt,
-				 &(tbinfo->dobj.dumpId), 1,
-				 dumpFn, tdinfo);
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
+					 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
+					 NULL, tbinfo->rolname,
+					 false, "TABLE DATA", SECTION_DATA,
+					 "", "", copyStmt,
+					 &(tbinfo->dobj.dumpId), 1,
+					 dumpFn, tdinfo);
 
 	destroyPQExpBuffer(copyBuf);
 	destroyPQExpBuffer(clistBuf);
@@ -1945,23 +1950,24 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout,
-				 tdinfo->dobj.catId,	/* catalog ID */
-				 tdinfo->dobj.dumpId,	/* dump ID */
-				 tbinfo->dobj.name,		/* Name */
-				 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
-				 NULL,			/* Tablespace */
-				 tbinfo->rolname,		/* Owner */
-				 false,			/* with oids */
-				 "MATERIALIZED VIEW DATA",		/* Desc */
-				 SECTION_POST_DATA,		/* Section */
-				 q->data,		/* Create */
-				 "",			/* Del */
-				 NULL,			/* Copy */
-				 tdinfo->dobj.dependencies,		/* Deps */
-				 tdinfo->dobj.nDeps,	/* # Deps */
-				 NULL,			/* Dumper */
-				 NULL);			/* Dumper Arg */
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout,
+					 tdinfo->dobj.catId,	/* catalog ID */
+					 tdinfo->dobj.dumpId,	/* dump ID */
+					 tbinfo->dobj.name,		/* Name */
+					 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
+					 NULL,			/* Tablespace */
+					 tbinfo->rolname,		/* Owner */
+					 false,			/* with oids */
+					 "MATERIALIZED VIEW DATA",		/* Desc */
+					 SECTION_POST_DATA,		/* Section */
+					 q->data,		/* Create */
+					 "",			/* Del */
+					 NULL,			/* Copy */
+					 tdinfo->dobj.dependencies,		/* Deps */
+					 tdinfo->dobj.nDeps,	/* # Deps */
+					 NULL,			/* Dumper */
+					 NULL);			/* Dumper Arg */
 
 	destroyPQExpBuffer(q);
 }
@@ -1977,7 +1983,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids)
 
 	for (i = 0; i < numTables; i++)
 	{
-		if (tblinfo[i].dobj.dump)
+		if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA)
 			makeTableDataInfo(dopt, &(tblinfo[i]), oids);
 	}
 }
@@ -2238,7 +2244,7 @@ guessConstraintInheritance(TableInfo *tblinfo, int numTables)
 			continue;
 
 		/* Don't bother computing anything for non-target tables, either */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		numParents = tbinfo->numParents;
@@ -2788,31 +2794,34 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 					  "SELECT pg_catalog.lo_unlink('%s');\n",
 					  binfo->dobj.name);
 
-	ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
-				 binfo->dobj.name,
-				 NULL, NULL,
-				 binfo->rolname, false,
-				 "BLOB", SECTION_PRE_DATA,
-				 cquery->data, dquery->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
+					 binfo->dobj.name,
+					 NULL, NULL,
+					 binfo->rolname, false,
+					 "BLOB", SECTION_PRE_DATA,
+					 cquery->data, dquery->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* set up tag for comment and/or ACL */
 	resetPQExpBuffer(cquery);
 	appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
 
 	/* Dump comment if any */
-	dumpComment(fout, cquery->data,
-				NULL, binfo->rolname,
-				binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, cquery->data,
+					NULL, binfo->rolname,
+					binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump security label if any */
-	dumpSecLabel(fout, cquery->data,
-				 NULL, binfo->rolname,
-				 binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, cquery->data,
+					 NULL, binfo->rolname,
+					 binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump ACL if any */
-	if (binfo->blobacl)
+	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
 		dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 				binfo->dobj.name, NULL, cquery->data,
 				NULL, binfo->rolname, binfo->blobacl);
@@ -2933,7 +2942,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
 		TableInfo  *tbinfo = &tblinfo[i];
 
 		/* Ignore row security on tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
 			continue;
 
 		if (g_verbose)
@@ -3073,15 +3082,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 		appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
 						  fmtId(polinfo->dobj.name));
 
-		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-					 polinfo->dobj.name,
-					 polinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "ROW SECURITY", SECTION_POST_DATA,
-					 query->data, "", NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+			ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+						 polinfo->dobj.name,
+						 polinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "ROW SECURITY", SECTION_POST_DATA,
+						 query->data, "", NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
 		destroyPQExpBuffer(query);
 		return;
@@ -3124,15 +3134,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 	appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
 	appendPQExpBuffer(delqry, " ON %s;\n", fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-				 polinfo->dobj.name,
-				 polinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "POLICY", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+					 polinfo->dobj.name,
+					 polinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "POLICY", SECTION_POST_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -3737,7 +3748,8 @@ getTypes(Archive *fout, int *numTypes)
 		 */
 		tyinfo[i].nDomChecks = 0;
 		tyinfo[i].domChecks = NULL;
-		if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			tyinfo[i].typtype == TYPTYPE_DOMAIN)
 			getDomainConstraints(fout, &(tyinfo[i]));
 
 		/*
@@ -3750,8 +3762,9 @@ getTypes(Archive *fout, int *numTypes)
 		 * should copy the base type's catId, but then it might capture the
 		 * pg_depend entries for the type, which we don't want.
 		 */
-		if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
-									tyinfo[i].typtype == TYPTYPE_RANGE))
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			(tyinfo[i].typtype == TYPTYPE_BASE ||
+			 tyinfo[i].typtype == TYPTYPE_RANGE))
 		{
 			stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
 			stinfo->dobj.objType = DO_SHELL_TYPE;
@@ -3767,7 +3780,7 @@ getTypes(Archive *fout, int *numTypes)
 			 * dump it if the I/O or canonicalize functions need to be dumped;
 			 * this is taken care of while sorting dependencies.
 			 */
-			stinfo->dobj.dump = false;
+			stinfo->dobj.dump = DUMP_COMPONENT_NONE;
 
 			/*
 			 * However, if dumping from pre-7.3, there will be no dependency
@@ -3785,7 +3798,7 @@ getTypes(Archive *fout, int *numTypes)
 				typoutput = atooid(PQgetvalue(res, i, i_typoutput));
 
 				funcInfo = findFuncByOid(typinput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3794,11 +3807,11 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 
 				funcInfo = findFuncByOid(typoutput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3807,7 +3820,7 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 			}
 		}
@@ -5255,10 +5268,11 @@ getTables(Archive *fout, int *numTables)
 		 * Decide whether we want to dump this table.
 		 */
 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
-			tblinfo[i].dobj.dump = false;
+			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
 		else
 			selectDumpableTable(&tblinfo[i], dopt);
-		tblinfo[i].interesting = tblinfo[i].dobj.dump;
+
+		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
 
@@ -5325,13 +5339,13 @@ getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
 
 		if (!OidIsValid(seqinfo->owning_tab))
 			continue;			/* not an owned sequence */
-		if (seqinfo->dobj.dump)
+		if (seqinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			continue;			/* no need to search */
 		owning_tab = findTableByOid(seqinfo->owning_tab);
 		if (owning_tab && owning_tab->dobj.dump)
 		{
 			seqinfo->interesting = true;
-			seqinfo->dobj.dump = true;
+			seqinfo->dobj.dump = DUMP_COMPONENT_ALL;
 		}
 	}
 }
@@ -5433,8 +5447,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 		if (!tbinfo->hasindex)
 			continue;
 
-		/* Ignore indexes of tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		/* Ignore indexes of tables whose definitions are not to be dumped */
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -5801,7 +5815,8 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -6140,7 +6155,8 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -8490,12 +8506,13 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
 			dumpBlob(fout, (BlobInfo *) dobj);
 			break;
 		case DO_BLOB_DATA:
-			ArchiveEntry(fout, dobj->catId, dobj->dumpId,
-						 dobj->name, NULL, NULL, "",
-						 false, "BLOBS", SECTION_DATA,
-						 "", "", NULL,
-						 NULL, 0,
-						 dumpBlobs, NULL);
+			if (dobj->dump & DUMP_COMPONENT_DATA)
+				ArchiveEntry(fout, dobj->catId, dobj->dumpId,
+							 dobj->name, NULL, NULL, "",
+							 false, "BLOBS", SECTION_DATA,
+							 "", "", NULL,
+							 NULL, 0,
+							 dumpBlobs, NULL);
 			break;
 		case DO_POLICY:
 			dumpPolicy(fout, (PolicyInfo *) dobj);
@@ -8543,26 +8560,31 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
-				 nspinfo->dobj.name,
-				 NULL, NULL,
-				 nspinfo->rolname,
-				 false, "SCHEMA", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
+					 nspinfo->dobj.name,
+					 NULL, NULL,
+					 nspinfo->rolname,
+					 false, "SCHEMA", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Schema Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, nspinfo->rolname,
-				nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, nspinfo->rolname,
-				 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, nspinfo->rolname,
+					nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, nspinfo->rolname,
+					 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
 
-	dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
-			qnspname, NULL, nspinfo->dobj.name, NULL,
-			nspinfo->rolname, nspinfo->nspacl);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
+				qnspname, NULL, nspinfo->dobj.name, NULL,
+				nspinfo->rolname, nspinfo->nspacl);
 
 	free(qnspname);
 
@@ -8672,22 +8694,26 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
 	appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
 
-	ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
-				 extinfo->dobj.name,
-				 NULL, NULL,
-				 "",
-				 false, "EXTENSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
+					 extinfo->dobj.name,
+					 NULL, NULL,
+					 "",
+					 false, "EXTENSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Extension Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+
+	if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
 
 	free(qextname);
 
@@ -8827,28 +8853,33 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -8960,28 +8991,33 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9030,28 +9066,33 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -9419,28 +9460,33 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9582,28 +9628,33 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "DOMAIN", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "DOMAIN", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Domain Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	/* Dump any per-constraint comments */
 	for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9615,10 +9666,13 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 						  fmtId(domcheck->dobj.name));
 		appendPQExpBuffer(labelq, "ON DOMAIN %s",
 						  qtypname);
-		dumpComment(fout, labelq->data,
-					tyinfo->dobj.namespace->dobj.name,
-					tyinfo->rolname,
-					domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+		if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpComment(fout, labelq->data,
+						tyinfo->dobj.namespace->dobj.name,
+						tyinfo->rolname,
+						domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
 		destroyPQExpBuffer(labelq);
 	}
 
@@ -9808,29 +9862,34 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9840,7 +9899,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	destroyPQExpBuffer(query);
 
 	/* Dump any per-column comments */
-	dumpCompositeTypeColComments(fout, tyinfo);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpCompositeTypeColComments(fout, tyinfo);
 }
 
 /*
@@ -9985,15 +10045,16 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
 					  fmtId(stinfo->dobj.name));
 
-	ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
-				 stinfo->dobj.name,
-				 stinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 stinfo->baseType->rolname, false,
-				 "SHELL TYPE", SECTION_PRE_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
+					 stinfo->dobj.name,
+					 stinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 stinfo->baseType->rolname, false,
+					 "SHELL TYPE", SECTION_PRE_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 }
@@ -10122,23 +10183,27 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
 
-	ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
-				 plang->dobj.name,
-				 lanschema, NULL, plang->lanowner,
-				 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
+					 plang->dobj.name,
+					 lanschema, NULL, plang->lanowner,
+					 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Proc Lang Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				plang->dobj.catId, 0, plang->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 plang->dobj.catId, 0, plang->dobj.dumpId);
-
-	if (plang->lanpltrusted)
+	if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					plang->dobj.catId, 0, plang->dobj.dumpId);
+
+	if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 plang->dobj.catId, 0, plang->dobj.dumpId);
+
+	if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 				qlanname, NULL, plang->dobj.name,
 				lanschema,
@@ -10787,28 +10852,33 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
-				 funcsig_tag,
-				 finfo->dobj.namespace->dobj.name,
-				 NULL,
-				 finfo->rolname, false,
-				 "FUNCTION", SECTION_PRE_DATA,
-				 q->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
+					 funcsig_tag,
+					 finfo->dobj.namespace->dobj.name,
+					 NULL,
+					 finfo->rolname, false,
+					 "FUNCTION", SECTION_PRE_DATA,
+					 q->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Function Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				finfo->dobj.namespace->dobj.name, finfo->rolname,
-				finfo->dobj.catId, 0, finfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 finfo->dobj.namespace->dobj.name, finfo->rolname,
-				 finfo->dobj.catId, 0, finfo->dobj.dumpId);
-
-	dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
-			funcsig, NULL, funcsig_tag,
-			finfo->dobj.namespace->dobj.name,
-			finfo->rolname, finfo->proacl);
+	if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					finfo->dobj.namespace->dobj.name, finfo->rolname,
+					finfo->dobj.catId, 0, finfo->dobj.dumpId);
+
+	if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 finfo->dobj.namespace->dobj.name, finfo->rolname,
+					 finfo->dobj.catId, 0, finfo->dobj.dumpId);
+
+	if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
+				funcsig, NULL, funcsig_tag,
+				finfo->dobj.namespace->dobj.name,
+				finfo->rolname, finfo->proacl);
 
 	PQclear(res);
 
@@ -10917,18 +10987,20 @@ dumpCast(Archive *fout, CastInfo *cast)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
 
-	ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "CAST", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "CAST", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Cast Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				cast->dobj.catId, 0, cast->dobj.dumpId);
+	if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					cast->dobj.catId, 0, cast->dobj.dumpId);
 
 	free(sourceType);
 	free(targetType);
@@ -11037,18 +11109,20 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &transform->dobj, labelq->data);
 
-	ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "TRANSFORM", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 transform->dobj.dependencies, transform->dobj.nDeps,
-				 NULL, NULL);
+	if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "TRANSFORM", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 transform->dobj.dependencies, transform->dobj.nDeps,
+					 NULL, NULL);
 
 	/* Dump Transform Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				transform->dobj.catId, 0, transform->dobj.dumpId);
+	if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					transform->dobj.catId, 0, transform->dobj.dumpId);
 
 	free(lanname);
 	free(transformType);
@@ -11291,20 +11365,22 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
-				 oprinfo->dobj.name,
-				 oprinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 oprinfo->rolname,
-				 false, "OPERATOR", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
+					 oprinfo->dobj.name,
+					 oprinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 oprinfo->rolname,
+					 false, "OPERATOR", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Comments */
-	dumpComment(fout, labelq->data,
-				oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
-				oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
+					oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -11800,20 +11876,22 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
-				 opcinfo->dobj.name,
-				 opcinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opcinfo->rolname,
-				 false, "OPERATOR CLASS", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
+					 opcinfo->dobj.name,
+					 opcinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opcinfo->rolname,
+					 false, "OPERATOR CLASS", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Class Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opcinfo->rolname,
-				opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opcinfo->rolname,
+					opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
 
 	free(amname);
 	destroyPQExpBuffer(query);
@@ -12114,20 +12192,22 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
-				 opfinfo->dobj.name,
-				 opfinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opfinfo->rolname,
-				 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
+					 opfinfo->dobj.name,
+					 opfinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opfinfo->rolname,
+					 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Family Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opfinfo->rolname,
-				opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opfinfo->rolname,
+					opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
 
 	free(amname);
 	PQclear(res_ops);
@@ -12204,20 +12284,22 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
-				 collinfo->dobj.name,
-				 collinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 collinfo->rolname,
-				 false, "COLLATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
+					 collinfo->dobj.name,
+					 collinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 collinfo->rolname,
+					 false, "COLLATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Collation Comments */
-	dumpComment(fout, labelq->data,
-				collinfo->dobj.namespace->dobj.name, collinfo->rolname,
-				collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					collinfo->dobj.namespace->dobj.name, collinfo->rolname,
+					collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12304,20 +12386,22 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
-				 convinfo->dobj.name,
-				 convinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 convinfo->rolname,
-				 false, "CONVERSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
+					 convinfo->dobj.name,
+					 convinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 convinfo->rolname,
+					 false, "CONVERSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Conversion Comments */
-	dumpComment(fout, labelq->data,
-				convinfo->dobj.namespace->dobj.name, convinfo->rolname,
-				convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					convinfo->dobj.namespace->dobj.name, convinfo->rolname,
+					convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12731,23 +12815,30 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
 
-	ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-				 aggsig_tag,
-				 agginfo->aggfn.dobj.namespace->dobj.name,
-				 NULL,
-				 agginfo->aggfn.rolname,
-				 false, "AGGREGATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
+					 agginfo->aggfn.dobj.dumpId,
+					 aggsig_tag,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 NULL,
+					 agginfo->aggfn.rolname,
+					 false, "AGGREGATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Aggregate Comments */
-	dumpComment(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					agginfo->aggfn.dobj.namespace->dobj.name,
+					agginfo->aggfn.rolname,
+					agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 agginfo->aggfn.rolname,
+					 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
 	/*
 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
@@ -12760,11 +12851,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	aggsig = format_function_signature(fout, &agginfo->aggfn, true);
 	aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
 
-	dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-			"FUNCTION",
-			aggsig, NULL, aggsig_tag,
-			agginfo->aggfn.dobj.namespace->dobj.name,
-			agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
+				"FUNCTION",
+				aggsig, NULL, aggsig_tag,
+				agginfo->aggfn.dobj.namespace->dobj.name,
+				agginfo->aggfn.rolname, agginfo->aggfn.proacl);
 
 	free(aggsig);
 	if (aggfullsig)
@@ -12832,20 +12924,22 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
-				 prsinfo->dobj.name,
-				 prsinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
+					 prsinfo->dobj.name,
+					 prsinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Parser Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -12920,20 +13014,22 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
-				 dictinfo->dobj.name,
-				 dictinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 dictinfo->rolname,
-				 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
+					 dictinfo->dobj.name,
+					 dictinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 dictinfo->rolname,
+					 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Dictionary Comments */
-	dumpComment(fout, labelq->data,
-				NULL, dictinfo->rolname,
-				dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, dictinfo->rolname,
+					dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -12987,20 +13083,22 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
-				 tmplinfo->dobj.name,
-				 tmplinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
+					 tmplinfo->dobj.name,
+					 tmplinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Template Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13116,20 +13214,22 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
-				 cfginfo->dobj.name,
-				 cfginfo->dobj.namespace->dobj.name,
-				 NULL,
-				 cfginfo->rolname,
-				 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
+					 cfginfo->dobj.name,
+					 cfginfo->dobj.namespace->dobj.name,
+					 NULL,
+					 cfginfo->rolname,
+					 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Configuration Comments */
-	dumpComment(fout, labelq->data,
-				NULL, cfginfo->rolname,
-				cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, cfginfo->rolname,
+					cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13183,27 +13283,30 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-				 fdwinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 fdwinfo->rolname,
-				 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+					 fdwinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 fdwinfo->rolname,
+					 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-			"FOREIGN DATA WRAPPER",
-			qfdwname, NULL, fdwinfo->dobj.name,
-			NULL, fdwinfo->rolname,
-			fdwinfo->fdwacl);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+				"FOREIGN DATA WRAPPER",
+				qfdwname, NULL, fdwinfo->dobj.name,
+				NULL, fdwinfo->rolname,
+				fdwinfo->fdwacl);
 
 	/* Dump Foreign Data Wrapper Comments */
-	dumpComment(fout, labelq->data,
-				NULL, fdwinfo->rolname,
-				fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, fdwinfo->rolname,
+					fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
 
 	free(qfdwname);
 
@@ -13276,33 +13379,37 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-				 srvinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 srvinfo->rolname,
-				 false, "SERVER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+					 srvinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 srvinfo->rolname,
+					 false, "SERVER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-			"FOREIGN SERVER",
-			qsrvname, NULL, srvinfo->dobj.name,
-			NULL, srvinfo->rolname,
-			srvinfo->srvacl);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+				"FOREIGN SERVER",
+				qsrvname, NULL, srvinfo->dobj.name,
+				NULL, srvinfo->rolname,
+				srvinfo->srvacl);
 
 	/* Dump user mappings */
-	dumpUserMappings(fout,
-					 srvinfo->dobj.name, NULL,
-					 srvinfo->rolname,
-					 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
+		dumpUserMappings(fout,
+						 srvinfo->dobj.name, NULL,
+						 srvinfo->rolname,
+						 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
 
 	/* Dump Foreign Server Comments */
-	dumpComment(fout, labelq->data,
-				NULL, srvinfo->rolname,
-				srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, srvinfo->rolname,
+					srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
 
 	free(qsrvname);
 
@@ -13465,15 +13572,16 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 		exit_horribly(NULL, "could not parse default ACL list (%s)\n",
 					  daclinfo->defaclacl);
 
-	ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
-				 tag->data,
+	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
+					 tag->data,
 	   daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
-				 NULL,
-				 daclinfo->defaclrole,
-				 false, "DEFAULT ACL", SECTION_POST_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 NULL,
+					 daclinfo->defaclrole,
+					 false, "DEFAULT ACL", SECTION_POST_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(tag);
 	destroyPQExpBuffer(q);
@@ -13842,19 +13950,16 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
 static void
 dumpTable(Archive *fout, TableInfo *tbinfo)
 {
-	DumpOptions *dopt = fout->dopt;
+	char		   *namecopy;
 
-	if (tbinfo->dobj.dump && !dopt->dataOnly)
-	{
-		char	   *namecopy;
-
-		if (tbinfo->relkind == RELKIND_SEQUENCE)
-			dumpSequence(fout, tbinfo);
-		else
-			dumpTableSchema(fout, tbinfo);
+	if (tbinfo->relkind == RELKIND_SEQUENCE)
+		dumpSequence(fout, tbinfo);
+	else
+		dumpTableSchema(fout, tbinfo);
 
-		/* Handle the ACL here */
-		namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	/* Handle the ACL here */
+	namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 				(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
 				"TABLE",
@@ -13862,47 +13967,49 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 				tbinfo->relacl);
 
-		/*
-		 * Handle column ACLs, if any.  Note: we pull these with a separate
-		 * query rather than trying to fetch them during getTableAttrs, so
-		 * that we won't miss ACLs on system columns.
-		 */
-		if (fout->remoteVersion >= 80400)
-		{
-			PQExpBuffer query = createPQExpBuffer();
-			PGresult   *res;
-			int			i;
+	/*
+	 * Handle column ACLs, if any.  Note: we pull these with a separate
+	 * query rather than trying to fetch them during getTableAttrs, so
+	 * that we won't miss ACLs on system columns.
+	 */
+	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
+	{
+		PQExpBuffer query = createPQExpBuffer();
+		PGresult   *res;
+		int			i;
 
-			appendPQExpBuffer(query,
-					   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
-							  "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
-							  "ORDER BY attnum",
-							  tbinfo->dobj.catId.oid);
-			res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+		appendPQExpBuffer(query,
+				   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
+						  "WHERE attrelid = '%u' AND NOT attisdropped "
+						  "AND attacl IS NOT NULL "
+						  "ORDER BY attnum",
+						  tbinfo->dobj.catId.oid);
+		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
-			for (i = 0; i < PQntuples(res); i++)
-			{
-				char	   *attname = PQgetvalue(res, i, 0);
-				char	   *attacl = PQgetvalue(res, i, 1);
-				char	   *attnamecopy;
-				char	   *acltag;
-
-				attnamecopy = pg_strdup(fmtId(attname));
-				acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
-				/* Column's GRANT type is always TABLE */
-				dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
-						namecopy, attnamecopy, acltag,
-						tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-						attacl);
-				free(attnamecopy);
-				free(acltag);
-			}
-			PQclear(res);
-			destroyPQExpBuffer(query);
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			char	   *attname = PQgetvalue(res, i, 0);
+			char	   *attacl = PQgetvalue(res, i, 1);
+			char	   *attnamecopy;
+			char	   *acltag;
+
+			attnamecopy = pg_strdup(fmtId(attname));
+			acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
+			/* Column's GRANT type is always TABLE */
+			dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
+					namecopy, attnamecopy, acltag,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					attacl);
+			free(attnamecopy);
+			free(acltag);
 		}
-
-		free(namecopy);
+		PQclear(res);
+		destroyPQExpBuffer(query);
 	}
+
+	free(namecopy);
+
+	return;
 }
 
 /*
@@ -14580,24 +14687,28 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
 			(tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
-				 tbinfo->rolname,
+					 tbinfo->rolname,
 			   (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
-				 reltypename,
-				 tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 reltypename,
+					 tbinfo->postponed_def ?
+						SECTION_POST_DATA : SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Table Comments */
-	dumpTableComment(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpTableComment(fout, tbinfo, reltypename);
 
 	/* Dump Table Security Labels */
-	dumpTableSecLabel(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpTableSecLabel(fout, tbinfo, reltypename);
 
 	/* Dump comments on inlined table constraints */
 	for (j = 0; j < tbinfo->ncheck; j++)
@@ -14607,7 +14718,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		if (constr->separate || !constr->conislocal)
 			continue;
 
-		dumpTableConstraintComment(fout, constr);
+		if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpTableConstraintComment(fout, constr);
 	}
 
 	destroyPQExpBuffer(q);
@@ -14654,15 +14766,16 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 	appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
 					  fmtId(tbinfo->attnames[adnum - 1]));
 
-	ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
-				 tbinfo->attnames[adnum - 1],
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "DEFAULT", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
+					 tbinfo->attnames[adnum - 1],
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "DEFAULT", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -14769,24 +14882,26 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 		appendPQExpBuffer(delq, "%s;\n",
 						  fmtId(indxinfo->dobj.name));
 
-		ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
-					 indxinfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "INDEX", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
+						 indxinfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "INDEX", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 
 	/* Dump Index Comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				indxinfo->dobj.catId, 0,
-				is_constraint ? indxinfo->indexconstraint :
-				indxinfo->dobj.dumpId);
+	if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					indxinfo->dobj.catId, 0,
+					is_constraint ? indxinfo->indexconstraint :
+					indxinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -14897,15 +15012,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'f')
 	{
@@ -14930,15 +15046,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "FK CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "FK CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'c' && tbinfo)
 	{
@@ -14965,15 +15082,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else if (coninfo->contype == 'c' && tbinfo == NULL)
@@ -15001,15 +15119,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tyinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tyinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tyinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tyinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else
@@ -15019,7 +15138,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 	}
 
 	/* Dump Constraint Comments --- only works for table constraints */
-	if (tbinfo && coninfo->separate)
+	if (tbinfo && coninfo->separate &&
+		coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
 		dumpTableConstraintComment(fout, coninfo);
 
 	destroyPQExpBuffer(q);
@@ -15043,10 +15163,12 @@ dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
 					  fmtId(coninfo->dobj.name));
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				coninfo->dobj.catId, 0,
+
+	if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					coninfo->dobj.catId, 0,
 			 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(labelq);
@@ -15241,15 +15363,16 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 		binary_upgrade_extension_member(query, &tbinfo->dobj,
 										labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE", SECTION_PRE_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE", SECTION_PRE_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/*
 	 * If the sequence is owned by a table column, emit the ALTER for it as a
@@ -15277,25 +15400,29 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 			appendPQExpBuffer(query, ".%s;\n",
 						fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
 
-			ArchiveEntry(fout, nilCatalogId, createDumpId(),
-						 tbinfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname,
-						 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
-						 query->data, "", NULL,
-						 &(tbinfo->dobj.dumpId), 1,
-						 NULL, NULL);
+			if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, nilCatalogId, createDumpId(),
+							 tbinfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname,
+							 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
+							 query->data, "", NULL,
+							 &(tbinfo->dobj.dumpId), 1,
+							 NULL, NULL);
 		}
 	}
 
 	/* Dump Sequence Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -15344,15 +15471,16 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(query, ", %s, %s);\n",
 					  last, (called ? "true" : "false"));
 
-	ArchiveEntry(fout, nilCatalogId, createDumpId(),
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE SET", SECTION_DATA,
-				 query->data, "", NULL,
-				 &(tbinfo->dobj.dumpId), 1,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, nilCatalogId, createDumpId(),
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE SET", SECTION_DATA,
+					 query->data, "", NULL,
+					 &(tbinfo->dobj.dumpId), 1,
+					 NULL, NULL);
 
 	PQclear(res);
 
@@ -15551,19 +15679,21 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
-				 tginfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "TRIGGER", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
+						 tginfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "TRIGGER", SECTION_POST_DATA,
+						 query->data, delqry->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -15628,14 +15758,16 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
 	appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
 					  fmtId(evtinfo->dobj.name));
 
-	ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
-				 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
-				 "EVENT TRIGGER", SECTION_POST_DATA,
-				 query->data, "", NULL, NULL, 0, NULL, NULL);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
+					 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
+					 "EVENT TRIGGER", SECTION_POST_DATA,
+					 query->data, "", NULL, NULL, 0, NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				NULL, evtinfo->evtowner,
-				evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, evtinfo->evtowner,
+					evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(labelq);
@@ -15752,21 +15884,23 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 	appendPQExpBuffer(labelq, " ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
-				 rinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "RULE", SECTION_POST_DATA,
-				 cmd->data, delcmd->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
+					 rinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "RULE", SECTION_POST_DATA,
+					 cmd->data, delcmd->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump rule comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -15940,7 +16074,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 			{
 				TableInfo  *configtbl;
 				Oid			configtbloid = atooid(extconfigarray[j]);
-				bool		dumpobj = curext->dobj.dump;
+				bool		dumpobj =
+								curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
 
 				configtbl = findTableByOid(configtbloid);
 				if (configtbl == NULL)
@@ -15950,7 +16085,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 				 * Tables of not-to-be-dumped extensions shouldn't be dumped
 				 * unless the table or its schema is explicitly included
 				 */
-				if (!curext->dobj.dump)
+				if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
 				{
 					/* check table explicitly requested */
 					if (table_include_oids.head != NULL &&
@@ -15959,7 +16094,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 						dumpobj = true;
 
 					/* check table's schema explicitly requested */
-					if (configtbl->dobj.namespace->dobj.dump)
+					if (configtbl->dobj.namespace->dobj.dump &
+							DUMP_COMPONENT_DATA)
 						dumpobj = true;
 				}
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 9a1d8f8..fd94d87 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -80,6 +80,18 @@ typedef enum
 	DO_POLICY
 } DumpableObjectType;
 
+/* component types of an object which can be selected for dumping */
+typedef uint32 DumpComponents;	/* a bitmask of dump object components */
+#define DUMP_COMPONENT_NONE			(0)
+#define DUMP_COMPONENT_DEFINITION	(1 << 0)
+#define DUMP_COMPONENT_DATA			(1 << 1)
+#define DUMP_COMPONENT_COMMENT		(1 << 2)
+#define DUMP_COMPONENT_SECLABEL		(1 << 3)
+#define DUMP_COMPONENT_ACL			(1 << 4)
+#define DUMP_COMPONENT_POLICY		(1 << 5)
+#define DUMP_COMPONENT_USERMAP		(1 << 6)
+#define DUMP_COMPONENT_ALL			(0xFFFF)
+
 typedef struct _dumpableObject
 {
 	DumpableObjectType objType;
@@ -87,7 +99,7 @@ typedef struct _dumpableObject
 	DumpId		dumpId;			/* assigned by AssignDumpId() */
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
-	bool		dump;			/* true if we want to dump this object */
+	DumpComponents dump;	/* bitmask of components to dump */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From e8eb906b2e2fdccc721a96e977e9a4eeb0ad98c8 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:44:21 -0400
Subject: [PATCH 3/5] In pg_dump, split "dump" into "dump" and "dump_contains"

Historically, the "dump" component of the namespace has been used
to decide if the objects inside of the namespace should be dumped
also.  Given that "dump" is now a bitmask and may be partial, and
we may want to dump out all components of the namespace object but
only some of the components of objects contained in the namespace,
create a "dump_contains" bitmask which will represent what components
of the objects inside of a namespace should be dumped out.

No behavior change here, but in preparation for a change where we
will dump out just the ACLs of objects in pg_catalog, but we might
not dump out the ACL of the pg_catalog namespace itself (for instance,
when it hasn't been changed from the value set at initdb time).
---
 src/bin/pg_dump/pg_dump.c | 21 ++++++++++++---------
 src/bin/pg_dump/pg_dump.h |  1 +
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 08a2e93..f02a6b9 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1308,24 +1308,25 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 */
 
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
-		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
+			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
 							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
 	 */
-	if (nsinfo->dobj.dump &&
+	if (nsinfo->dobj.dump_contains &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1347,7 +1348,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 												   tbinfo->dobj.catId.oid) ?
 								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
-		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
+		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
 
 	/*
 	 * In any case, a table can be excluded by an exclusion switch
@@ -1404,7 +1405,8 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
+	/* Dump based on if the contents of the namespace are being dumped */
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
 }
 
 /*
@@ -1421,6 +1423,7 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	/* Default ACLs can't be extension members */
 
 	if (dinfo->dobj.namespace)
+		/* default ACLs are considered part of the namespace */
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
 		dinfo->dobj.dump = dopt->include_everything ?
@@ -1507,7 +1510,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	 * non-namespace-associated items, dump if we're dumping "everything".
 	 */
 	if (dobj->namespace)
-		dobj->dump = dobj->namespace->dobj.dump;
+		dobj->dump = dobj->namespace->dobj.dump_contains;
 	else
 		dobj->dump = dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index fd94d87..508e6b9 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -100,6 +100,7 @@ typedef struct _dumpableObject
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
 	DumpComponents dump;	/* bitmask of components to dump */
+	DumpComponents dump_contains;	/* as above, but for contained objects */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From 30cbb798572235ee0b99cf0c6b730c990ceb7f61 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 12:43:24 -0400
Subject: [PATCH 4/5] In pg_dump, include pg_catalog and extension ACLs, if
 changed

Now that all of the infrastructure exists, add in the ability to
dump out the ACLs of the objects inside of pg_catalog or the ACLs
for objects which are members of extensions, but only if they have
been changed from their original values.

The original values are tracked in pg_init_privs.  When pg_dump'ing
9.6-and-above databases, we will dump out the ACLs for all objects
in pg_catalog and the ACLs for all extension members, where the ACL
has been changed from the original value which was set during either
initdb or CREATE EXTENSION.

This should not change dumps against pre-9.6 databases.
---
 src/bin/initdb/initdb.c      |    6 +-
 src/bin/pg_dump/dumputils.c  |  120 +++-
 src/bin/pg_dump/dumputils.h  |    4 +-
 src/bin/pg_dump/pg_dump.c    | 1231 ++++++++++++++++++++++++++++++++++++------
 src/bin/pg_dump/pg_dump.h    |    8 +
 src/bin/pg_dump/pg_dumpall.c |    6 +-
 6 files changed, 1185 insertions(+), 190 deletions(-)

diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 858667b..d2e25ae 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -2002,8 +2002,10 @@ setup_privileges(FILE *cmdfd)
 	char	  **priv_lines;
 	static char *privileges_setup[] = {
 		"UPDATE pg_class "
-		"  SET relacl = E'{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
-		"  WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n\n",
+		"  SET relacl = (SELECT array_agg(a.acl) FROM "
+		" (SELECT '=r/$POSTGRES_SUPERUSERNAME' as acl "
+		"  UNION SELECT unnest(acldefault('r',10))) as a) "
+		"  WHERE relkind IN ('r', 'v') AND relacl IS NULL;\n\n",
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
 		"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 24ba5c8..55c819e 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -480,6 +480,7 @@ parsePGArray(const char *atext, char ***itemarray, int *nitems)
  *		TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
  *		FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
  *	acls: the ACL string fetched from the database
+ *	racls: the ACL string of any initial-but-now-revoked privileges
  *	owner: username of object owner (will be passed through fmtId); can be
  *		NULL or empty string to indicate "no owner known"
  *	prefix: string to prefix to each generated command; typically empty
@@ -496,13 +497,15 @@ parsePGArray(const char *atext, char ***itemarray, int *nitems)
  */
 bool
 buildACLCommands(const char *name, const char *subname,
-				 const char *type, const char *acls, const char *owner,
-				 const char *prefix, int remoteVersion,
+				 const char *type, const char *acls, const char *racls,
+				 const char *owner, const char *prefix, int remoteVersion,
 				 PQExpBuffer sql)
 {
 	bool		ok = true;
-	char	  **aclitems;
-	int			naclitems;
+	char	  **aclitems = NULL;
+	char	  **raclitems = NULL;
+	int			naclitems = 0;
+	int			nraclitems = 0;
 	int			i;
 	PQExpBuffer grantee,
 				grantor,
@@ -512,18 +515,31 @@ buildACLCommands(const char *name, const char *subname,
 				secondsql;
 	bool		found_owner_privs = false;
 
-	if (strlen(acls) == 0)
+	if (strlen(acls) == 0 && strlen(racls) == 0)
 		return true;			/* object has default permissions */
 
 	/* treat empty-string owner same as NULL */
 	if (owner && *owner == '\0')
 		owner = NULL;
 
-	if (!parsePGArray(acls, &aclitems, &naclitems))
+	if (strlen(acls) != 0)
 	{
-		if (aclitems)
-			free(aclitems);
-		return false;
+		if (!parsePGArray(acls, &aclitems, &naclitems))
+		{
+			if (aclitems)
+				free(aclitems);
+			return false;
+		}
+	}
+
+	if (strlen(racls) != 0)
+	{
+		if (!parsePGArray(racls, &raclitems, &nraclitems))
+		{
+			if (raclitems)
+				free(raclitems);
+			return false;
+		}
 	}
 
 	grantee = createPQExpBuffer();
@@ -542,14 +558,74 @@ buildACLCommands(const char *name, const char *subname,
 	secondsql = createPQExpBuffer();
 
 	/*
-	 * Always start with REVOKE ALL FROM PUBLIC, so that we don't have to
-	 * wire-in knowledge about the default public privileges for different
-	 * kinds of objects.
+	 * If no revoke ACLs have been provided then always start with
+	 * REVOKE ALL FROM PUBLIC, so that we don't have to wire-in knowledge about
+	 * the default public privileges for different kinds of objects.
+	 *
+	 * If revoke ACLs have been provided, then include them in 'firstsql'.
+	 * Revoke ACLs happen when an object starts out life with a set of
+	 * privileges (eg: GRANT SELECT ON pg_class TO PUBLIC;) and the user has
+	 * decided to revoke those rights.  Since those objects come into being
+	 * with those default privileges, we have to revoke them to match what the
+	 * current state of affairs is.  Note that we only started explicitly
+	 * tracking such initial rights in 9.6, and prior to that all initial
+	 * rights are actually handled by the simple 'REVOKE ALL .. FROM PUBLIC'
+	 * case, for initdb-created objects.  Prior to 9.6, we didn't handle
+	 * extensions correctly, but we do now by tracking their initial privilegs,
+	 * in the same way we track initdb initial privileges, see pg_init_privs.
 	 */
-	appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
-	if (subname)
-		appendPQExpBuffer(firstsql, "(%s)", subname);
-	appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+	if (remoteVersion < 90600 && nraclitems == 0)
+	{
+		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
+		if (subname)
+			appendPQExpBuffer(firstsql, "(%s)", subname);
+		appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+	}
+	else
+	{
+		/* Scan individual ACL items */
+		for (i = 0; i < nraclitems; i++)
+		{
+			if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion,
+							  grantee, grantor, privs, privswgo))
+			{
+				ok = false;
+				break;
+			}
+
+			if (privs->len > 0 || privswgo->len > 0)
+			{
+				if (privs->len > 0)
+				{
+					appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s %s FROM ",
+									  prefix, privs->data, type, name);
+					if (grantee->len == 0)
+						appendPQExpBufferStr(firstsql, "PUBLIC;\n");
+					else if (strncmp(grantee->data, "group ",
+									 strlen("group ")) == 0)
+						appendPQExpBuffer(firstsql, "GROUP %s;\n",
+									fmtId(grantee->data + strlen("group ")));
+					else
+						appendPQExpBuffer(firstsql, "%s;\n",
+										  fmtId(grantee->data));
+				}
+				if (privswgo->len > 0)
+				{
+					appendPQExpBuffer(firstsql,
+								"%sREVOKE GRANT OPTION FOR %s ON %s %s FROM ",
+									  prefix, privswgo->data, type, name);
+					if (grantee->len == 0)
+						appendPQExpBufferStr(firstsql, "PUBLIC");
+					else if (strncmp(grantee->data, "group ",
+									 strlen("group ")) == 0)
+						appendPQExpBuffer(firstsql, "GROUP %s",
+									fmtId(grantee->data + strlen("group ")));
+					else
+						appendPQExpBufferStr(firstsql, fmtId(grantee->data));
+				}
+			}
+		}
+	}
 
 	/*
 	 * We still need some hacking though to cover the case where new default
@@ -580,7 +656,7 @@ buildACLCommands(const char *name, const char *subname,
 
 		if (privs->len > 0 || privswgo->len > 0)
 		{
-			if (owner
+			if (remoteVersion < 90600 && owner
 				&& strcmp(grantee->data, owner) == 0
 				&& strcmp(grantor->data, owner) == 0)
 			{
@@ -659,7 +735,7 @@ buildACLCommands(const char *name, const char *subname,
 	/*
 	 * If we didn't find any owner privs, the owner must have revoked 'em all
 	 */
-	if (!found_owner_privs && owner)
+	if (remoteVersion < 90600 && !found_owner_privs && owner)
 	{
 		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
 		if (subname)
@@ -677,7 +753,11 @@ buildACLCommands(const char *name, const char *subname,
 	destroyPQExpBuffer(firstsql);
 	destroyPQExpBuffer(secondsql);
 
-	free(aclitems);
+	if (aclitems)
+		free(aclitems);
+
+	if (raclitems)
+		free(raclitems);
 
 	return ok;
 }
@@ -717,7 +797,7 @@ buildDefaultACLCommands(const char *type, const char *nspname,
 		appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
 
 	result = buildACLCommands("", NULL,
-							  type, acls, owner,
+							  type, acls, "", owner,
 							  prefix->data, remoteVersion,
 							  sql);
 
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 4941ec0..34e24fa 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -85,8 +85,8 @@ extern void appendByteaLiteral(PQExpBuffer buf,
 				   bool std_strings);
 extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
 extern bool buildACLCommands(const char *name, const char *subname,
-				 const char *type, const char *acls, const char *owner,
-				 const char *prefix, int remoteVersion,
+				 const char *type, const char *acls, const char *racls,
+				 const char *owner, const char *prefix, int remoteVersion,
 				 PQExpBuffer sql);
 extern bool buildDefaultACLCommands(const char *type, const char *nspname,
 						const char *acls, const char *owner,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index f02a6b9..df2cd24 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -203,7 +203,7 @@ static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 		const char *type, const char *name, const char *subname,
 		const char *tag, const char *nspname, const char *owner,
-		const char *acls);
+		const char *acls, const char *racls);
 
 static void getDependencies(Archive *fout);
 static void BuildArchiveDependencies(Archive *fout);
@@ -1265,7 +1265,7 @@ expand_table_name_patterns(Archive *fout,
  * Returns true if object is an extension member, else false.
  */
 static bool
-checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
+checkExtensionMembership(DumpableObject *dobj, Archive *fout)
 {
 	ExtensionInfo *ext = findOwningExtension(dobj->catId);
 
@@ -1278,12 +1278,26 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
 	addObjectDependency(dobj, ext->dobj.dumpId);
 
 	/*
-	 * Normally, mark the member object as not to be dumped.  But in binary
-	 * upgrades, we still dump the members individually, since the idea is to
-	 * exactly reproduce the database contents rather than replace the
-	 * extension contents with something different.
+	 * In 9.6 and above, mark the member object to have any non-initial ACL,
+	 * policies, and security lables dumped.
+	 *
+	 * Note that any initial ACLs (see pg_init_privs) will be removed when we
+	 * extract the information about the object.  We don't provide support for
+	 * initial policies and security labels and it seems unlikely for those
+	 * to ever exist, but we may have to revisit this later.
+	 *
+	 * Prior to 9.6, we do not include any extension member components.
+	 *
+	 * In binary upgrades, we still dump all components of the members
+	 * individually, since the idea is to exactly reproduce the database
+	 * contents rather than replace the extension contents with something
+	 * different.
 	 */
-	if (!dopt->binary_upgrade)
+	if (!fout->dopt->binary_upgrade && fout->remoteVersion >= 90600)
+		dobj->dump = DUMP_COMPONENT_ACL |
+					 DUMP_COMPONENT_SECLABEL |
+					 DUMP_COMPONENT_POLICY;
+	else if (!fout->dopt->binary_upgrade)
 		dobj->dump = DUMP_COMPONENT_NONE;
 	else
 		dobj->dump = ext->dobj.dump;
@@ -1296,9 +1310,9 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
  *		Mark a namespace as to be dumped or not
  */
 static void
-selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
+selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
 {
-	if (checkExtensionMembership(&nsinfo->dobj, dopt))
+	if (checkExtensionMembership(&nsinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1314,6 +1328,14 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
 							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+	else if (fout->remoteVersion >= 90600 &&
+			 strncmp(nsinfo->dobj.name, "pg_catalog", 10) == 0)
+		/*
+		 * In 9.6 and above, we dump out any ACLs defined in pg_catalog,
+		 * if they are interesting (and not the original ACLs which were
+		 * set at initdb time, see pg_init_privs).
+		 */
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
@@ -1334,9 +1356,9 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
  *		Mark a table as to be dumped or not
  */
 static void
-selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
+selectDumpableTable(TableInfo *tbinfo, Archive *fout)
 {
-	if (checkExtensionMembership(&tbinfo->dobj, dopt))
+	if (checkExtensionMembership(&tbinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1373,7 +1395,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
  * object (the table or base type).
  */
 static void
-selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
+selectDumpableType(TypeInfo *tyinfo, Archive *fout)
 {
 	/* skip complex types, except for standalone composite types */
 	if (OidIsValid(tyinfo->typrelid) &&
@@ -1402,7 +1424,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 		 */
 	}
 
-	if (checkExtensionMembership(&tyinfo->dobj, dopt))
+	if (checkExtensionMembership(&tyinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/* Dump based on if the contents of the namespace are being dumped */
@@ -1440,15 +1462,15 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
  * OID is in the range reserved for initdb.
  */
 static void
-selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
+selectDumpableCast(CastInfo *cast, Archive *fout)
 {
-	if (checkExtensionMembership(&cast->dobj, dopt))
+	if (checkExtensionMembership(&cast->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		cast->dobj.dump = dopt->include_everything ?
+		cast->dobj.dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1461,15 +1483,15 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
  * language's OID is in the range reserved for initdb.
  */
 static void
-selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
+selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
 {
-	if (checkExtensionMembership(&plang->dobj, dopt))
+	if (checkExtensionMembership(&plang->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = dopt->include_everything ?
+		plang->dobj.dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1500,9 +1522,9 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
  * Use this only for object types without a special-case routine above.
  */
 static void
-selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
+selectDumpableObject(DumpableObject *dobj, Archive *fout)
 {
-	if (checkExtensionMembership(dobj, dopt))
+	if (checkExtensionMembership(dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1512,7 +1534,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	if (dobj->namespace)
 		dobj->dump = dobj->namespace->dobj.dump_contains;
 	else
-		dobj->dump = dopt->include_everything ?
+		dobj->dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -2706,12 +2728,19 @@ dumpStdStrings(Archive *AH)
 static void
 getBlobs(Archive *fout)
 {
+	DumpOptions *dopt = fout->dopt;
 	PQExpBuffer blobQry = createPQExpBuffer();
 	BlobInfo   *binfo;
 	DumpableObject *bdata;
 	PGresult   *res;
 	int			ntups;
 	int			i;
+	int			i_oid;
+	int			i_lomowner;
+	int			i_lomacl;
+	int			i_rlomacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Verbose message */
 	if (g_verbose)
@@ -2720,53 +2749,122 @@ getBlobs(Archive *fout)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(l.lomacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(l.lomacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('L',l.lomowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+						"EXCEPT "
+						" SELECT unnest(l.lomacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('L',l.lomowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(l.lomacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(l.lomacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+						"EXCEPT "
+						" SELECT unnest(l.lomacl)) as a)";
+	}
+
 	/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
-	if (fout->remoteVersion >= 90000)
+	if (fout->remoteVersion >= 90600)
 		appendPQExpBuffer(blobQry,
-						  "SELECT oid, (%s lomowner) AS rolname, lomacl"
+						  "SELECT l.oid, (%s l.lomowner) AS rolname, "
+						  "%s AS lomacl, "
+						  "%s AS rlomacl "
+						  "FROM pg_largeobject_metadata l "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(l.oid = pip.objoid AND pip.classoid = "
+			  "(SELECT oid FROM pg_class WHERE relname = 'pg_largeobject')"
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	else if (fout->remoteVersion >= 90000)
+		appendPQExpBuffer(blobQry,
+						  "SELECT oid, (%s lomowner) AS rolname, lomacl, "
+						  "NULL AS rlomacl"
 						  " FROM pg_largeobject_metadata",
 						  username_subquery);
 	else if (fout->remoteVersion >= 70100)
 		appendPQExpBufferStr(blobQry,
-							 "SELECT DISTINCT loid, NULL::oid, NULL::oid"
+							 "SELECT DISTINCT loid, NULL::oid, NULL, "
+							 "NULL AS rlomacl "
 							 " FROM pg_largeobject");
 	else
 		appendPQExpBufferStr(blobQry,
-							 "SELECT oid, NULL::oid, NULL::oid"
+							 "SELECT oid, NULL::oid, NULL, "
+							 "NULL AS rlomacl "
 							 " FROM pg_class WHERE relkind = 'l'");
 
 	res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
 
+	i_oid = PQfnumber(res, "oid");
+	i_lomowner = PQfnumber(res, "rolname");
+	i_lomacl = PQfnumber(res, "lomacl");
+	i_rlomacl = PQfnumber(res, "rlomacl");
+
 	ntups = PQntuples(res);
-	if (ntups > 0)
+
+	/*
+	 * Each large object has its own BLOB archive entry.
+	 */
+	binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+
+	for (i = 0; i < ntups; i++)
 	{
-		/*
-		 * Each large object has its own BLOB archive entry.
-		 */
-		binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+		binfo[i].dobj.objType = DO_BLOB;
+		binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
+		binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+		AssignDumpId(&binfo[i].dobj);
 
-		for (i = 0; i < ntups; i++)
-		{
-			binfo[i].dobj.objType = DO_BLOB;
-			binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
-			binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
-			AssignDumpId(&binfo[i].dobj);
-
-			binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
-			if (!PQgetisnull(res, i, 1))
-				binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
-			else
-				binfo[i].rolname = "";
-			if (!PQgetisnull(res, i, 2))
-				binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
-			else
-				binfo[i].blobacl = NULL;
-		}
+		binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
+		binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
+		binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
+		binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
 
-		/*
-		 * If we have any large objects, a "BLOBS" archive entry is needed.
-		 * This is just a placeholder for sorting; it carries no data now.
-		 */
+		if (PQgetisnull(res, i, i_lomacl) && PQgetisnull(res, i, i_rlomacl))
+			binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
+	}
+
+	/*
+	 * If we have any large objects, a "BLOBS" archive entry is needed.
+	 * This is just a placeholder for sorting; it carries no data now.
+	 */
+	if (ntups > 0)
+	{
 		bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
 		bdata->objType = DO_BLOB_DATA;
 		bdata->catId = nilCatalogId;
@@ -2827,7 +2925,7 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
 		dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 				binfo->dobj.name, NULL, cquery->data,
-				NULL, binfo->rolname, binfo->blobacl);
+				NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl);
 
 	destroyPQExpBuffer(cquery);
 	destroyPQExpBuffer(dquery);
@@ -3358,6 +3456,9 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	int			i_nspname;
 	int			i_rolname;
 	int			i_nspacl;
+	int			i_rnspacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/*
 	 * Before 7.3, there are no real namespaces; create two dummy entries, one
@@ -3375,7 +3476,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[0].rolname = pg_strdup("");
 		nsinfo[0].nspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[0], dopt);
+		selectDumpableNamespace(&nsinfo[0], fout);
 
 		nsinfo[1].dobj.objType = DO_NAMESPACE;
 		nsinfo[1].dobj.catId.tableoid = 0;
@@ -3385,7 +3486,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[1].rolname = pg_strdup("");
 		nsinfo[1].nspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[1], dopt);
+		selectDumpableNamespace(&nsinfo[1], fout);
 
 		*numNamespaces = 2;
 
@@ -3398,13 +3499,103 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	selectSourceSchema(fout, "pg_catalog");
 
 	/*
+	 * To get the delta from what the permissions were at creation time
+	 * (either initdb or CREATE EXTENSION) vs. what they are now, we have to
+	 * look at two things:
+	 *
+	 * What privileges have been added, which we calculate by extracting all
+	 * the current privileges and then removing those which existed at creation
+	 * time, or which were there by default for the object.
+	 *
+	 * What privileges have been removed, which we calculate by extracting the
+	 * privileges as they were at creation time, and any privileges which were
+	 * there by default for the object, and then removing the current
+	 * privileges.
+	 *
+	 * If the ACL column is simply NULL then we just pass that through as a
+	 * NULL for both the 'privileges granted' and 'privileges revoked'.  No
+	 * ACL-related command will be included in such a case.
+	 *
+	 * We always perform this delta on ACLs which are created at initdb time,
+	 * since those will already be in place in any cluster we are restoring
+	 * into (binary upgrade or not).
+	 *
+	 * However, in binary upgrade mode, we perform the delta, in both
+	 * directions, without consideration for the initial privileges (those
+	 * tracked by pg_init_privs) on extension objects (but we must still
+	 * consider the default ACLs for the object), since we're dumping and
+	 * restoring those objects completely and the CREATE EXTENSION script
+	 * won't be re-run.
+	 */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(n.nspacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(n.nspacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('n',n.nspowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+						"EXCEPT "
+						" SELECT unnest(n.nspacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('n',n.nspowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(n.nspacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(n.nspacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+						"EXCEPT "
+						" SELECT unnest(n.nspacl)) as a)";
+	}
+
+	/*
 	 * we fetch all namespaces including system ones, so that every object we
 	 * read in can be linked to a containing namespace.
 	 */
-	appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
-					  "(%s nspowner) AS rolname, "
-					  "nspacl FROM pg_namespace",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+		appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "%s as nspacl, "
+						  "%s as rnspacl "
+						  "FROM pg_namespace n "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (n.oid = pip.objoid AND pip.classoid = "
+					"(SELECT oid FROM pg_class WHERE relname = 'pg_namespace') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	else
+		appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "nspacl, NULL as rnspacl FROM pg_namespace",
+						  username_subquery);
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -3417,6 +3608,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	i_nspname = PQfnumber(res, "nspname");
 	i_rolname = PQfnumber(res, "rolname");
 	i_nspacl = PQfnumber(res, "nspacl");
+	i_rnspacl = PQfnumber(res, "rnspacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -3427,9 +3619,21 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
 		nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
+		nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
 
 		/* Decide whether to dump this namespace */
-		selectDumpableNamespace(&nsinfo[i], dopt);
+		selectDumpableNamespace(&nsinfo[i], fout);
+
+		/*
+		 * Do not try to dump ACL if the ACL is empty or the default.
+		 *
+		 * This is useful because, for some schemas/objects, the only component
+		 * we are going to try and dump is the ACL and if we can remove that
+		 * then 'dump' goes to zero/false and we don't consider this object for
+		 * dumping at all later on.
+		 */
+		if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl))
+			nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(nsinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
@@ -3589,6 +3793,7 @@ getTypes(Archive *fout, int *numTypes)
 	int			i_typname;
 	int			i_typnamespace;
 	int			i_typacl;
+	int			i_rtypacl;
 	int			i_rolname;
 	int			i_typinput;
 	int			i_typoutput;
@@ -3598,6 +3803,8 @@ getTypes(Archive *fout, int *numTypes)
 	int			i_typtype;
 	int			i_typisdefined;
 	int			i_isarray;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/*
 	 * we include even the built-in types because those may be used as array
@@ -3618,10 +3825,81 @@ getTypes(Archive *fout, int *numTypes)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90200)
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(t.typacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(t.typacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('T',t.typowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+						"EXCEPT "
+						" SELECT unnest(t.typacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('T',t.typowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(t.typacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(t.typacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+						"EXCEPT "
+						" SELECT unnest(t.typacl)) as a)";
+	}
+
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
+						  "t.typnamespace, "
+						  "%s AS typacl, "
+						  "%s AS rtypacl, "
+						  "(%s t.typowner) AS rolname, "
+						  "t.typinput::oid AS typinput, "
+						  "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, "
+						  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
+						  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
+						  "t.typtype, t.typisdefined, "
+						  "t.typname[0] = '_' AND t.typelem != 0 AND "
+						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
+						  "FROM pg_type t "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (t.oid = pip.objoid AND pip.classoid = "
+					"(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) ",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery);
+	}
+	else if (fout->remoteVersion >= 90200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, typacl, "
+						  "typnamespace, typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3636,7 +3914,7 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 80300)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, NULL AS typacl, "
+						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3651,7 +3929,7 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, NULL AS typacl, "
+						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3665,7 +3943,7 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 70100)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "0::oid AS typnamespace, NULL AS typacl, "
+						  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3681,7 +3959,7 @@ getTypes(Archive *fout, int *numTypes)
 		appendPQExpBuffer(query, "SELECT "
 		 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
 						  "oid, typname, "
-						  "0::oid AS typnamespace, NULL AS typacl, "
+						  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3704,6 +3982,7 @@ getTypes(Archive *fout, int *numTypes)
 	i_typname = PQfnumber(res, "typname");
 	i_typnamespace = PQfnumber(res, "typnamespace");
 	i_typacl = PQfnumber(res, "typacl");
+	i_rtypacl = PQfnumber(res, "rtypacl");
 	i_rolname = PQfnumber(res, "rolname");
 	i_typinput = PQfnumber(res, "typinput");
 	i_typoutput = PQfnumber(res, "typoutput");
@@ -3727,6 +4006,7 @@ getTypes(Archive *fout, int *numTypes)
 						  tyinfo[i].dobj.catId.oid);
 		tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
+		tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
 		tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
 		tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
 		tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
@@ -3744,7 +4024,11 @@ getTypes(Archive *fout, int *numTypes)
 			tyinfo[i].isArray = false;
 
 		/* Decide whether we want to dump it */
-		selectDumpableType(&tyinfo[i], dopt);
+		selectDumpableType(&tyinfo[i], fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl))
+			tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		/*
 		 * If it's a domain, fetch info about its constraints, if any
@@ -3852,7 +4136,6 @@ getTypes(Archive *fout, int *numTypes)
 OprInfo *
 getOperators(Archive *fout, int *numOprs)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -3938,7 +4221,7 @@ getOperators(Archive *fout, int *numOprs)
 		oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(oprinfo[i].dobj), dopt);
+		selectDumpableObject(&(oprinfo[i].dobj), fout);
 
 		if (strlen(oprinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
@@ -3962,7 +4245,6 @@ getOperators(Archive *fout, int *numOprs)
 CollInfo *
 getCollations(Archive *fout, int *numCollations)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4024,7 +4306,7 @@ getCollations(Archive *fout, int *numCollations)
 		collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(collinfo[i].dobj), dopt);
+		selectDumpableObject(&(collinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -4044,7 +4326,6 @@ getCollations(Archive *fout, int *numCollations)
 ConvInfo *
 getConversions(Archive *fout, int *numConversions)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4106,7 +4387,7 @@ getConversions(Archive *fout, int *numConversions)
 		convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(convinfo[i].dobj), dopt);
+		selectDumpableObject(&(convinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -4126,7 +4407,6 @@ getConversions(Archive *fout, int *numConversions)
 OpclassInfo *
 getOpclasses(Archive *fout, int *numOpclasses)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4198,7 +4478,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(opcinfo[i].dobj), dopt);
+		selectDumpableObject(&(opcinfo[i].dobj), fout);
 
 		if (fout->remoteVersion >= 70300)
 		{
@@ -4225,7 +4505,6 @@ getOpclasses(Archive *fout, int *numOpclasses)
 OpfamilyInfo *
 getOpfamilies(Archive *fout, int *numOpfamilies)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4287,7 +4566,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(opfinfo[i].dobj), dopt);
+		selectDumpableObject(&(opfinfo[i].dobj), fout);
 
 		if (fout->remoteVersion >= 70300)
 		{
@@ -4328,22 +4607,108 @@ getAggregates(Archive *fout, int *numAggs)
 	int			i_proargtypes;
 	int			i_rolname;
 	int			i_aggacl;
+	int			i_raggacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(p.proacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(p.proacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('f',p.proowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+						"EXCEPT "
+						" SELECT unnest(p.proacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('f',p.proowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(p.proacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(p.proacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+						"EXCEPT "
+						" SELECT unnest(p.proacl)) as a)";
+	}
+
 	/*
-	 * Find all user-defined aggregates.  See comment in getFuncs() for the
+	 * Find all interesting aggregates.  See comment in getFuncs() for the
 	 * rationale behind the filtering logic.
 	 */
-
-	if (fout->remoteVersion >= 80200)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
+						  "p.proname AS aggname, "
+						  "p.pronamespace AS aggnamespace, "
+						  "p.pronargs, p.proargtypes, "
+						  "(%s p.proowner) AS rolname, "
+						  "%s AS aggacl, "
+						  "%s AS raggacl "
+						  "FROM pg_proc p "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(p.oid = pip.objoid AND pip.classoid = "
+						"(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE p.proisagg AND ("
+						  "p.pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
+	}
+	else if (fout->remoteVersion >= 80200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
 						  "pronamespace AS aggnamespace, "
 						  "pronargs, proargtypes, "
 						  "(%s proowner) AS rolname, "
-						  "proacl AS aggacl "
+						  "proacl AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_proc p "
 						  "WHERE proisagg AND ("
 						  "pronamespace != "
@@ -4366,7 +4731,8 @@ getAggregates(Archive *fout, int *numAggs)
 						  "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
 						  "proargtypes, "
 						  "(%s proowner) AS rolname, "
-						  "proacl AS aggacl "
+						  "proacl AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_proc "
 						  "WHERE proisagg "
 						  "AND pronamespace != "
@@ -4380,7 +4746,8 @@ getAggregates(Archive *fout, int *numAggs)
 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 						  "aggbasetype AS proargtypes, "
 						  "(%s aggowner) AS rolname, "
-						  "NULL AS aggacl "
+						  "NULL AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_aggregate "
 						  "where oid > '%u'::oid",
 						  username_subquery,
@@ -4395,7 +4762,8 @@ getAggregates(Archive *fout, int *numAggs)
 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 						  "aggbasetype AS proargtypes, "
 						  "(%s aggowner) AS rolname, "
-						  "NULL AS aggacl "
+						  "NULL AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_aggregate "
 						  "where oid > '%u'::oid",
 						  username_subquery,
@@ -4417,6 +4785,7 @@ getAggregates(Archive *fout, int *numAggs)
 	i_proargtypes = PQfnumber(res, "proargtypes");
 	i_rolname = PQfnumber(res, "rolname");
 	i_aggacl = PQfnumber(res, "aggacl");
+	i_raggacl = PQfnumber(res, "raggacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -4436,6 +4805,7 @@ getAggregates(Archive *fout, int *numAggs)
 		agginfo[i].aggfn.lang = InvalidOid;		/* not currently interesting */
 		agginfo[i].aggfn.prorettype = InvalidOid;		/* not saved */
 		agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
+		agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
 		agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
 		if (agginfo[i].aggfn.nargs == 0)
 			agginfo[i].aggfn.argtypes = NULL;
@@ -4452,7 +4822,11 @@ getAggregates(Archive *fout, int *numAggs)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(agginfo[i].aggfn.dobj), dopt);
+		selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl))
+			agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4488,17 +4862,69 @@ getFuncs(Archive *fout, int *numFuncs)
 	int			i_proargtypes;
 	int			i_prorettype;
 	int			i_proacl;
+	int			i_rproacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(p.proacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(p.proacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('f',p.proowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+						"EXCEPT "
+						" SELECT unnest(p.proacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('f',p.proowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(p.proacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(p.proacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+						"EXCEPT "
+						" SELECT unnest(p.proacl)) as a)";
+	}
+
 	/*
-	 * Find all user-defined functions.  Normally we can exclude functions in
-	 * pg_catalog, which is worth doing since there are several thousand of
-	 * 'em.  However, there are some extensions that create functions in
-	 * pg_catalog.  In normal dumps we can still ignore those --- but in
-	 * binary-upgrade mode, we must dump the member objects of the extension,
-	 * so be sure to fetch any such functions.
+	 * Find all interesting functions.  We include functions in pg_catalog, if
+	 * they have an ACL different from what we set at initdb time (which is
+	 * saved in pg_init_privs for us to perform this check).  There may also be
+	 * functions which are members of extensions which we must dump if we are
+	 * in binary upgrade mode (we'll mark those functions as to-be-dumped when
+	 * we check if the extension is to-be-dumped and we're in binary upgrade
+	 * mode).
 	 *
 	 * Also, in 9.2 and up, exclude functions that are internally dependent on
 	 * something else, since presumably those will be created as a result of
@@ -4507,13 +4933,50 @@ getFuncs(Archive *fout, int *numFuncs)
 	 * because the constructors don't have any dependencies the range type
 	 * doesn't have; otherwise we might not get creation ordering correct.
 	 */
-
-	if (fout->remoteVersion >= 70300)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query,
+						  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
+						  "p.pronargs, p.proargtypes, p.prorettype, "
+						  "%s AS proacl, "
+						  "%s AS rproacl, "
+						  "p.pronamespace, "
+						  "(%s p.proowner) AS rolname "
+						  "FROM pg_proc p "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(p.oid = pip.objoid AND pip.classoid = "
+						"(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE NOT proisagg "
+						  "AND NOT EXISTS (SELECT 1 FROM pg_depend "
+						  "WHERE classid = 'pg_proc'::regclass AND "
+						  "objid = p.oid AND deptype = 'i') AND ("
+						  "pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+								 "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
+	}
+	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query,
 						  "SELECT tableoid, oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, proacl, "
-						  "pronamespace, "
+						  "NULL as rproacl, pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc p "
 						  "WHERE NOT proisagg AND ("
@@ -4541,6 +5004,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "SELECT tableoid, oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, "
 						  "NULL AS proacl, "
+						  "NULL AS rproacl, "
 						  "0::oid AS pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc "
@@ -4557,6 +5021,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, "
 						  "NULL AS proacl, "
+						  "NULL AS rproacl, "
 						  "0::oid AS pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc "
@@ -4583,6 +5048,7 @@ getFuncs(Archive *fout, int *numFuncs)
 	i_proargtypes = PQfnumber(res, "proargtypes");
 	i_prorettype = PQfnumber(res, "prorettype");
 	i_proacl = PQfnumber(res, "proacl");
+	i_rproacl = PQfnumber(res, "rproacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -4599,6 +5065,7 @@ getFuncs(Archive *fout, int *numFuncs)
 		finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
 		finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
 		finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
+		finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
 		finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
 		if (finfo[i].nargs == 0)
 			finfo[i].argtypes = NULL;
@@ -4610,7 +5077,11 @@ getFuncs(Archive *fout, int *numFuncs)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(finfo[i].dobj), dopt);
+		selectDumpableObject(&(finfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl))
+			finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(finfo[i].rolname) == 0)
 			write_msg(NULL,
@@ -4627,7 +5098,7 @@ getFuncs(Archive *fout, int *numFuncs)
 
 /*
  * getTables
- *	  read all the user-defined tables (no indexes, no catalogs)
+ *	  read all the tables (no indexes)
  * in the system catalogs return them in the TableInfo* structure
  *
  * numTables is set to the number of tables read in
@@ -4647,6 +5118,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_relnamespace;
 	int			i_relkind;
 	int			i_relacl;
+	int			i_rrelacl;
 	int			i_rolname;
 	int			i_relchecks;
 	int			i_relhastriggers;
@@ -4671,6 +5143,8 @@ getTables(Archive *fout, int *numTables)
 	int			i_toastreloptions;
 	int			i_reloftype;
 	int			i_relpages;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
@@ -4695,15 +5169,115 @@ getTables(Archive *fout, int *numTables)
 	 * we cannot correctly identify inherited columns, owned sequences, etc.
 	 */
 
-	if (fout->remoteVersion >= 90500)
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(c.relacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(c.relacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('r',c.relowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+						"EXCEPT "
+						" SELECT unnest(c.relacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('r',c.relowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(c.relacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(c.relacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+						"EXCEPT "
+						" SELECT unnest(c.relacl)) as a)";
+	}
+
+	if (fout->remoteVersion >= 90600)
 	{
 		/*
 		 * Left join to pick up dependency info linking sequences to their
 		 * owning column, if any (note this dependency is AUTO as of 8.2)
+		 *
+		 * Left join to detect if any privileges are still as-set-at-init,
+		 * in which case we won't dump out ACL commands for those.
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "%s AS relacl, %s as rrelacl, "
+						  "c.relkind, c.relnamespace, "
+						  "(%s c.relowner) AS rolname, "
+						  "c.relchecks, c.relhastriggers, "
+						  "c.relhasindex, c.relhasrules, c.relhasoids, "
+						  "c.relrowsecurity, c.relforcerowsecurity, "
+						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
+						  "tc.relfrozenxid AS tfrozenxid, "
+						  "tc.relminmxid AS tminmxid, "
+						  "c.relpersistence, c.relispopulated, "
+						  "c.relreplident, c.relpages, "
+						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+						  "d.refobjid AS owning_tab, "
+						  "d.refobjsubid AS owning_col, "
+						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
+						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
+						  "tc.reloptions AS toast_reloptions "
+						  "FROM pg_class c "
+						  "LEFT JOIN pg_depend d ON "
+						  "(c.relkind = '%c' AND "
+						  "d.classid = c.tableoid AND d.objid = c.oid AND "
+						  "d.objsubid = 0 AND "
+						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
+					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(c.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_class') AND pip.objsubid = 0) "
+				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
+						  "ORDER BY c.oid",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery,
+						  RELKIND_SEQUENCE,
+						  RELKIND_RELATION, RELKIND_SEQUENCE,
+						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
+	}
+	else if (fout->remoteVersion >= 90500)
+	{
+		/*
+		 * Left join to pick up dependency info linking sequences to their
+		 * owning column, if any (note this dependency is AUTO as of 8.2)
+		 */
+		appendPQExpBuffer(query,
+						  "SELECT c.tableoid, c.oid, c.relname, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4744,7 +5318,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4786,7 +5361,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4828,7 +5404,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4868,7 +5445,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4907,7 +5485,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4946,7 +5525,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 					  "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4985,7 +5565,7 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, relname, "
-						  "relacl, relkind, relnamespace, "
+						  "relacl, NULL as rrelacl, relkind, relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 						  "relhasindex, relhasrules, relhasoids, "
@@ -5023,7 +5603,7 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, relname, "
-						  "relacl, relkind, relnamespace, "
+						  "relacl, NULL as rrelacl, relkind, relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 						  "relhasindex, relhasrules, relhasoids, "
@@ -5056,7 +5636,8 @@ getTables(Archive *fout, int *numTables)
 	else if (fout->remoteVersion >= 70200)
 	{
 		appendPQExpBuffer(query,
-						  "SELECT tableoid, oid, relname, relacl, relkind, "
+						  "SELECT tableoid, oid, relname, relacl, "
+						  "NULL as rrelacl, relkind, "
 						  "0::oid AS relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5084,7 +5665,8 @@ getTables(Archive *fout, int *numTables)
 	{
 		/* all tables have oids in 7.1 */
 		appendPQExpBuffer(query,
-						  "SELECT tableoid, oid, relname, relacl, relkind, "
+						  "SELECT tableoid, oid, relname, relacl, "
+						  "NULL as rrelacl, relkind, "
 						  "0::oid AS relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5118,7 +5700,7 @@ getTables(Archive *fout, int *numTables)
 		appendPQExpBuffer(query,
 						  "SELECT "
 		"(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
-						  "oid, relname, relacl, "
+						  "oid, relname, relacl, NULL as rrelacl, "
 						  "CASE WHEN relhasrules and relkind = 'r' "
 					  "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
 					  "             r.ev_class = c.oid AND r.ev_type = '1') "
@@ -5172,6 +5754,7 @@ getTables(Archive *fout, int *numTables)
 	i_relname = PQfnumber(res, "relname");
 	i_relnamespace = PQfnumber(res, "relnamespace");
 	i_relacl = PQfnumber(res, "relacl");
+	i_rrelacl = PQfnumber(res, "rrelacl");
 	i_relkind = PQfnumber(res, "relkind");
 	i_rolname = PQfnumber(res, "rolname");
 	i_relchecks = PQfnumber(res, "relchecks");
@@ -5226,6 +5809,7 @@ getTables(Archive *fout, int *numTables)
 						  tblinfo[i].dobj.catId.oid);
 		tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
+		tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
 		tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
 		tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
 		tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
@@ -5273,7 +5857,7 @@ getTables(Archive *fout, int *numTables)
 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
 			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
 		else
-			selectDumpableTable(&tblinfo[i], dopt);
+			selectDumpableTable(&tblinfo[i], fout);
 
 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
@@ -6359,7 +6943,6 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 EventTriggerInfo *
 getEventTriggers(Archive *fout, int *numEventTriggers)
 {
-	DumpOptions *dopt = fout->dopt;
 	int			i;
 	PQExpBuffer query;
 	PGresult   *res;
@@ -6429,7 +7012,7 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 		evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(evtinfo[i].dobj), dopt);
+		selectDumpableObject(&(evtinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -6465,17 +7048,88 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	int			i_laninline;
 	int			i_lanvalidator;
 	int			i_lanacl;
+	int			i_rlanacl;
 	int			i_lanowner;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90000)
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(l.lanacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(l.lanacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('l',l.lanowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+						"EXCEPT "
+						" SELECT unnest(l.lanacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('l',l.lanowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(l.lanacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(l.lanacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+						"EXCEPT "
+						" SELECT unnest(l.lanacl)) as a)";
+	}
+
+	if (fout->remoteVersion >= 90600)
+	{
+		/* pg_language has a laninline column */
+		appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
+						  "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
+						  "l.laninline, l.lanvalidator, "
+						  "%s AS lanacl, "
+						  "%s AS rlanacl, "
+						  "(%s l.lanowner) AS lanowner "
+						  "FROM pg_language l "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (l.oid = pip.objoid AND pip.classoid = "
+					"(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE l.lanispl "
+						  "ORDER BY l.oid",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery);
+	}
+	else if (fout->remoteVersion >= 90000)
 	{
 		/* pg_language has a laninline column */
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
-						  "laninline, lanvalidator, lanacl, "
+						  "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
 						  "(%s lanowner) AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6488,6 +7142,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "(%s lanowner) AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6500,6 +7155,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "(%s '10') AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6512,6 +7168,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "(%s '1') AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6524,6 +7181,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6534,6 +7192,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+						  "NULL AS rlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6546,6 +7205,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 						  "oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+						  "NULL AS rlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6568,6 +7228,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	i_laninline = PQfnumber(res, "laninline");
 	i_lanvalidator = PQfnumber(res, "lanvalidator");
 	i_lanacl = PQfnumber(res, "lanacl");
+	i_rlanacl = PQfnumber(res, "rlanacl");
 	i_lanowner = PQfnumber(res, "lanowner");
 
 	for (i = 0; i < ntups; i++)
@@ -6583,10 +7244,15 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
 		planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
 		planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
+		planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
 		planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
 
 		/* Decide whether we want to dump it */
-		selectDumpableProcLang(&(planginfo[i]), dopt);
+		selectDumpableProcLang(&(planginfo[i]), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl))
+			planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (fout->remoteVersion < 70300)
 		{
@@ -6619,7 +7285,6 @@ getProcLangs(Archive *fout, int *numProcLangs)
 CastInfo *
 getCasts(Archive *fout, int *numCasts)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -6725,7 +7390,7 @@ getCasts(Archive *fout, int *numCasts)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableCast(&(castinfo[i]), dopt);
+		selectDumpableCast(&(castinfo[i]), fout);
 	}
 
 	PQclear(res);
@@ -6761,7 +7426,6 @@ get_language_name(Archive *fout, Oid langid)
 TransformInfo *
 getTransforms(Archive *fout, int *numTransforms)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -6836,7 +7500,7 @@ getTransforms(Archive *fout, int *numTransforms)
 		free(lanname);
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(transforminfo[i].dobj), dopt);
+		selectDumpableObject(&(transforminfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7447,7 +8111,6 @@ shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
 TSParserInfo *
 getTSParsers(Archive *fout, int *numTSParsers)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7520,7 +8183,7 @@ getTSParsers(Archive *fout, int *numTSParsers)
 		prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(prsinfo[i].dobj), dopt);
+		selectDumpableObject(&(prsinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7540,7 +8203,6 @@ getTSParsers(Archive *fout, int *numTSParsers)
 TSDictInfo *
 getTSDictionaries(Archive *fout, int *numTSDicts)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7606,7 +8268,7 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 			dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(dictinfo[i].dobj), dopt);
+		selectDumpableObject(&(dictinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7626,7 +8288,6 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 TSTemplateInfo *
 getTSTemplates(Archive *fout, int *numTSTemplates)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7684,7 +8345,7 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 		tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(tmplinfo[i].dobj), dopt);
+		selectDumpableObject(&(tmplinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7704,7 +8365,6 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 TSConfigInfo *
 getTSConfigurations(Archive *fout, int *numTSConfigs)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7763,7 +8423,7 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 		cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(cfginfo[i].dobj), dopt);
+		selectDumpableObject(&(cfginfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7796,7 +8456,10 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	int			i_fdwhandler;
 	int			i_fdwvalidator;
 	int			i_fdwacl;
+	int			i_rfdwacl;
 	int			i_fdwoptions;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Before 8.4, there are no foreign-data wrappers */
 	if (fout->remoteVersion < 80400)
@@ -7805,17 +8468,89 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 		return NULL;
 	}
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(f.fdwacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(f.fdwacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('F',f.fdwowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+						"EXCEPT "
+						" SELECT unnest(f.fdwacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('F',f.fdwowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(f.fdwacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(f.fdwacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+						"EXCEPT "
+						" SELECT unnest(f.fdwacl)) as a)";
+	}
+
 	query = createPQExpBuffer();
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90100)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
+						  "(%s f.fdwowner) AS rolname, "
+						  "f.fdwhandler::pg_catalog.regproc, "
+						  "f.fdwvalidator::pg_catalog.regproc, "
+						  "%s AS fdwacl, "
+						  "%s AS rfdwacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.fdwoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS fdwoptions "
+						  "FROM pg_foreign_data_wrapper f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+		"(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_data_wrapper') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	}
+	else if (fout->remoteVersion >= 90100)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
 						  "(%s fdwowner) AS rolname, "
 						  "fdwhandler::pg_catalog.regproc, "
 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
+						  "NULL as rfdwacl, "
 						  "array_to_string(ARRAY("
 						  "SELECT quote_ident(option_name) || ' ' || "
 						  "quote_literal(option_value) "
@@ -7831,6 +8566,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 						  "(%s fdwowner) AS rolname, "
 						  "'-' AS fdwhandler, "
 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
+						  "NULL as rfdwacl, "
 						  "array_to_string(ARRAY("
 						  "SELECT quote_ident(option_name) || ' ' || "
 						  "quote_literal(option_value) "
@@ -7855,6 +8591,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	i_fdwhandler = PQfnumber(res, "fdwhandler");
 	i_fdwvalidator = PQfnumber(res, "fdwvalidator");
 	i_fdwacl = PQfnumber(res, "fdwacl");
+	i_rfdwacl = PQfnumber(res, "rfdwacl");
 	i_fdwoptions = PQfnumber(res, "fdwoptions");
 
 	for (i = 0; i < ntups; i++)
@@ -7870,9 +8607,14 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 		fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
 		fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
 		fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
+		fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(fdwinfo[i].dobj), dopt);
+		selectDumpableObject(&(fdwinfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl))
+			fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -7906,7 +8648,10 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	int			i_srvtype;
 	int			i_srvversion;
 	int			i_srvacl;
+	int			i_rsrvacl;
 	int			i_srvoptions;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Before 8.4, there are no foreign servers */
 	if (fout->remoteVersion < 80400)
@@ -7915,22 +8660,96 @@ getForeignServers(Archive *fout, int *numForeignServers)
 		return NULL;
 	}
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+					   "(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(f.srvacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+					   ") as a) "
+					   "ELSE "
+					   "(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   " (SELECT unnest(f.srvacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('S',f.srvowner)) "
+					   ") as a) "
+					   "END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						"(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+						"EXCEPT "
+						" SELECT unnest(f.srvacl)) as a) "
+						"ELSE "
+						" (SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('S',f.srvowner)) as acl "
+						"EXCEPT "
+						 "SELECT unnest(f.srvacl)) as a) "
+						"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+					   "array_agg(acl) END FROM "
+					   "(SELECT unnest(f.srvacl) as acl EXCEPT "
+					   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+					   ") as a)";
+		racl_subquery = "(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+						"array_agg(acl) END FROM "
+						"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+						"EXCEPT "
+						" SELECT unnest(f.srvacl)) as a)";
+	}
+
 	query = createPQExpBuffer();
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
-					  "(%s srvowner) AS rolname, "
-					  "srvfdw, srvtype, srvversion, srvacl,"
-					  "array_to_string(ARRAY("
-					  "SELECT quote_ident(option_name) || ' ' || "
-					  "quote_literal(option_value) "
-					  "FROM pg_options_to_table(srvoptions) "
-					  "ORDER BY option_name"
-					  "), E',\n    ') AS srvoptions "
-					  "FROM pg_foreign_server",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
+						  "(%s f.srvowner) AS rolname, "
+						  "f.srvfdw, f.srvtype, f.srvversion, "
+						  "%s AS srvacl, "
+						  "%s AS rsrvacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions "
+						  "FROM pg_foreign_server f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+		"(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_server') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	}
+	else
+	{
+		appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
+						  "(%s srvowner) AS rolname, "
+						  "srvfdw, srvtype, srvversion, srvacl, "
+						  "NULL AS rsrvacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions "
+						  "FROM pg_foreign_server",
+						  username_subquery);
+	}
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -7947,6 +8766,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	i_srvtype = PQfnumber(res, "srvtype");
 	i_srvversion = PQfnumber(res, "srvversion");
 	i_srvacl = PQfnumber(res, "srvacl");
+	i_rsrvacl = PQfnumber(res, "rsrvacl");
 	i_srvoptions = PQfnumber(res, "srvoptions");
 
 	for (i = 0; i < ntups; i++)
@@ -7963,9 +8783,14 @@ getForeignServers(Archive *fout, int *numForeignServers)
 		srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
 		srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
 		srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
+		srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(srvinfo[i].dobj), dopt);
+		selectDumpableObject(&(srvinfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl))
+			srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8587,7 +9412,7 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
 				qnspname, NULL, nspinfo->dobj.name, NULL,
-				nspinfo->rolname, nspinfo->nspacl);
+				nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl);
 
 	free(qnspname);
 
@@ -8882,7 +9707,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9020,7 +9845,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9095,7 +9920,7 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -9489,7 +10314,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9657,7 +10482,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	/* Dump any per-constraint comments */
 	for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9892,7 +10717,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -10210,7 +11035,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 				qlanname, NULL, plang->dobj.name,
 				lanschema,
-				plang->lanowner, plang->lanacl);
+				plang->lanowner, plang->lanacl, plang->rlanacl);
 
 	free(qlanname);
 
@@ -10881,7 +11706,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
 				funcsig, NULL, funcsig_tag,
 				finfo->dobj.namespace->dobj.name,
-				finfo->rolname, finfo->proacl);
+				finfo->rolname, finfo->proacl, finfo->rproacl);
 
 	PQclear(res);
 
@@ -12859,7 +13684,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 				"FUNCTION",
 				aggsig, NULL, aggsig_tag,
 				agginfo->aggfn.dobj.namespace->dobj.name,
-				agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+				agginfo->aggfn.rolname, agginfo->aggfn.proacl,
+				agginfo->aggfn.rproacl);
 
 	free(aggsig);
 	if (aggfullsig)
@@ -13303,7 +14129,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 				"FOREIGN DATA WRAPPER",
 				qfdwname, NULL, fdwinfo->dobj.name,
 				NULL, fdwinfo->rolname,
-				fdwinfo->fdwacl);
+				fdwinfo->fdwacl, fdwinfo->rfdwacl);
 
 	/* Dump Foreign Data Wrapper Comments */
 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13399,7 +14225,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 				"FOREIGN SERVER",
 				qsrvname, NULL, srvinfo->dobj.name,
 				NULL, srvinfo->rolname,
-				srvinfo->srvacl);
+				srvinfo->srvacl, srvinfo->rsrvacl);
 
 	/* Dump user mappings */
 	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
@@ -13605,13 +14431,15 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
  * 'owner' is the owner, NULL if there is no owner (for languages).
  * 'acls' is the string read out of the fooacl system catalog field;
  *		it will be parsed here.
+ * 'racls' contains any initial ACLs that the object had which have now been
+ * 		revoked by the user, it will also be parsed here.
  *----------
  */
 static void
 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 		const char *type, const char *name, const char *subname,
 		const char *tag, const char *nspname, const char *owner,
-		const char *acls)
+		const char *acls, const char *racls)
 {
 	DumpOptions *dopt = fout->dopt;
 	PQExpBuffer sql;
@@ -13626,7 +14454,7 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 
 	sql = createPQExpBuffer();
 
-	if (!buildACLCommands(name, subname, type, acls, owner,
+	if (!buildACLCommands(name, subname, type, acls, racls, owner,
 						  "", fout->remoteVersion, sql))
 		exit_horribly(NULL,
 					"could not parse ACL list (%s) for object \"%s\" (%s)\n",
@@ -13953,6 +14781,7 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
 static void
 dumpTable(Archive *fout, TableInfo *tbinfo)
 {
+	DumpOptions	   *dopt = fout->dopt;
 	char		   *namecopy;
 
 	if (tbinfo->relkind == RELKIND_SEQUENCE)
@@ -13968,7 +14797,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 				"TABLE",
 				namecopy, NULL, tbinfo->dobj.name,
 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tbinfo->relacl);
+				tbinfo->relacl, tbinfo->rrelacl);
 
 	/*
 	 * Handle column ACLs, if any.  Note: we pull these with a separate
@@ -13980,19 +14809,95 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 		PQExpBuffer query = createPQExpBuffer();
 		PGresult   *res;
 		int			i;
+		char	   *acl_subquery;
+		char	   *racl_subquery;
+
+		/* see comments in getNamespaces */
+		if (dopt->binary_upgrade)
+		{
+			acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+						   "(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+						   "array_agg(acl) END FROM "
+						   "(SELECT unnest(at.attacl) as acl EXCEPT "
+						   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+						   ") as a) "
+						   "ELSE "
+						   "(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+						   "array_agg(acl) END FROM "
+					   " (SELECT unnest(at.attacl) as acl EXCEPT "
+	"  SELECT unnest(acldefault('c',c.relowner)) "
+						   ") as a) "
+						   "END";
+			racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+							"(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+							"array_agg(acl) END FROM "
+							"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+							"EXCEPT "
+							" SELECT unnest(at.attacl)) as a) "
+							"ELSE "
+							" (SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+							"array_agg(acl) END FROM "
+	"(SELECT unnest(acldefault('c',c.relowner)) as acl "
+							"EXCEPT "
+							 "SELECT unnest(at.attacl)) as a) "
+							"END";
+		}
+		else
+		{
+			acl_subquery = "(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+						   "array_agg(acl) END FROM "
+						   "(SELECT unnest(at.attacl) as acl EXCEPT "
+						   " (SELECT unnest(pip.initprivs) "
+	"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+						   ") as a)";
+			racl_subquery = "(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+							"array_agg(acl) END FROM "
+							"((SELECT unnest(pip.initprivs) as acl "
+	"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+							"EXCEPT "
+							" SELECT unnest(at.attacl)) as a)";
+		}
+
+		if (fout->remoteVersion >= 90600)
+		{
+			appendPQExpBuffer(query,
+					   "SELECT at.attname, "
+					   "%s AS attacl, "
+					   "%s AS rattacl "
+					   "FROM pg_catalog.pg_attribute at "
+					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+					   "LEFT JOIN pg_init_privs pip ON "
+					   "(pip.classoid = "
+				   "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
+				   " at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
+							  "WHERE at.attrelid = '%u' AND "
+							  "NOT at.attisdropped "
+							  "AND at.attacl IS NOT NULL "
+							  "ORDER BY at.attnum",
+							  acl_subquery,
+							  racl_subquery,
+							  tbinfo->dobj.catId.oid);
+		}
+		else
+		{
+			appendPQExpBuffer(query,
+							  "SELECT attname, attacl, NULL as rattacl "
+							  "FROM pg_catalog.pg_attribute "
+							  "WHERE attrelid = '%u' AND NOT attisdropped "
+							  "AND attacl IS NOT NULL "
+							  "ORDER BY attnum",
+							  tbinfo->dobj.catId.oid);
+		}
 
-		appendPQExpBuffer(query,
-				   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
-						  "WHERE attrelid = '%u' AND NOT attisdropped "
-						  "AND attacl IS NOT NULL "
-						  "ORDER BY attnum",
-						  tbinfo->dobj.catId.oid);
 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
 		for (i = 0; i < PQntuples(res); i++)
 		{
 			char	   *attname = PQgetvalue(res, i, 0);
 			char	   *attacl = PQgetvalue(res, i, 1);
+			char	   *rattacl = PQgetvalue(res, i, 2);
 			char	   *attnamecopy;
 			char	   *acltag;
 
@@ -14002,7 +14907,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 			dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
 					namecopy, attnamecopy, acltag,
 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-					attacl);
+					attacl, rattacl);
 			free(attnamecopy);
 			free(acltag);
 		}
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 508e6b9..5f0fd77 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -112,6 +112,7 @@ typedef struct _namespaceInfo
 	DumpableObject dobj;
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *nspacl;
+	char	   *rnspacl;
 } NamespaceInfo;
 
 typedef struct _extensionInfo
@@ -134,6 +135,7 @@ typedef struct _typeInfo
 	 */
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *typacl;
+	char	   *rtypacl;
 	Oid			typelem;
 	Oid			typrelid;
 	char		typrelkind;		/* 'r', 'v', 'c', etc */
@@ -163,6 +165,7 @@ typedef struct _funcInfo
 	Oid		   *argtypes;
 	Oid			prorettype;
 	char	   *proacl;
+	char	   *rproacl;
 } FuncInfo;
 
 /* AggInfo is a superset of FuncInfo */
@@ -212,6 +215,7 @@ typedef struct _tableInfo
 	DumpableObject dobj;
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *relacl;
+	char	   *rrelacl;
 	char		relkind;
 	char		relpersistence; /* relation persistence */
 	bool		relispopulated; /* relation is populated */
@@ -380,6 +384,7 @@ typedef struct _procLangInfo
 	Oid			laninline;
 	Oid			lanvalidator;
 	char	   *lanacl;
+	char	   *rlanacl;
 	char	   *lanowner;		/* name of owner, or empty string */
 } ProcLangInfo;
 
@@ -449,6 +454,7 @@ typedef struct _fdwInfo
 	char	   *fdwvalidator;
 	char	   *fdwoptions;
 	char	   *fdwacl;
+	char	   *rfdwacl;
 } FdwInfo;
 
 typedef struct _foreignServerInfo
@@ -459,6 +465,7 @@ typedef struct _foreignServerInfo
 	char	   *srvtype;
 	char	   *srvversion;
 	char	   *srvacl;
+	char	   *rsrvacl;
 	char	   *srvoptions;
 } ForeignServerInfo;
 
@@ -475,6 +482,7 @@ typedef struct _blobInfo
 	DumpableObject dobj;
 	char	   *rolname;
 	char	   *blobacl;
+	char	   *rblobacl;
 } BlobInfo;
 
 /*
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index be6b4a8..b5ca606 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1112,8 +1112,8 @@ dumpTablespaces(PGconn *conn)
 							  fspcname, spcoptions);
 
 		if (!skip_acls &&
-			!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner,
-							  "", server_version, buf))
+			!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, "",
+							  spcowner, "", server_version, buf))
 		{
 			fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
 					progname, spcacl, fspcname);
@@ -1443,7 +1443,7 @@ dumpCreateDB(PGconn *conn)
 		}
 
 		if (!skip_acls &&
-			!buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner,
+			!buildACLCommands(fdbname, NULL, "DATABASE", dbacl, "", dbowner,
 							  "", server_version, buf))
 		{
 			fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
-- 
2.5.0


From 51e31a774bff407b30aee9c9db88ec1561b46d77 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 14 Mar 2016 11:05:25 -0400
Subject: [PATCH 5/5] Use GRANT system to manage access to sensitive functions

Now that pg_dump will properly dump out any ACL changes made to
functions which exist in pg_catalog, switch to using the GRANT system
to manage access to those functions.

This means removing 'if (!superuser()) ereport()' checks from the
functions themselves and then REVOKEing EXECUTE right from 'public' for
these functions in system_views.sql.
---
 src/backend/access/transam/xlogfuncs.c | 48 +++++++++++++---------------------
 src/backend/catalog/system_views.sql   | 20 ++++++++++++++
 src/backend/postmaster/pgstat.c        | 24 +++++++----------
 src/backend/utils/adt/misc.c           | 16 +++++-------
 4 files changed, 53 insertions(+), 55 deletions(-)

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 9ec6b2a..f7daa8e 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -43,6 +43,9 @@
  * contains the user-supplied label string (typically this would be used
  * to tell where the backup dump will be stored) and the starting time and
  * starting WAL location for the dump.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_start_backup(PG_FUNCTION_ARGS)
@@ -55,11 +58,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
 
 	backupidstr = text_to_cstring(backupid);
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		   errmsg("must be superuser or replication role to run a backup")));
-
 	/* Make sure we can open the directory with tablespaces in it */
 	dir = AllocateDir("pg_tblspc");
 	if (!dir)
@@ -86,17 +84,15 @@ pg_start_backup(PG_FUNCTION_ARGS)
  * record for that and the file is for informational and debug purposes only.
  *
  * Note: different from CancelBackup which just cancels online backup mode.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_stop_backup(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	stoppoint;
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		 (errmsg("must be superuser or replication role to run a backup"))));
-
 	stoppoint = do_pg_stop_backup(NULL, true, NULL);
 
 	PG_RETURN_LSN(stoppoint);
@@ -104,17 +100,15 @@ pg_stop_backup(PG_FUNCTION_ARGS)
 
 /*
  * pg_switch_xlog: switch to next xlog file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_switch_xlog(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	switchpoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-			 (errmsg("must be superuser to switch transaction log files"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -131,6 +125,9 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
 
 /*
  * pg_create_restore_point: a named point for restore
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_create_restore_point(PG_FUNCTION_ARGS)
@@ -139,11 +136,6 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
 	char	   *restore_name_str;
 	XLogRecPtr	restorepoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to create a restore point"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -365,15 +357,13 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_pause - pause recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -387,15 +377,13 @@ pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_resume - resume recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_resume(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 9ae1ef4..c867451 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -997,3 +997,23 @@ RETURNS text[]
 LANGUAGE INTERNAL
 STRICT IMMUTABLE
 AS 'parse_ident';
+
+-- The default permissions for functions mean that anyone can execute them.
+-- A number of functions shouldn't be executable by just anyone, but rather
+-- than use explicit 'superuser()' checks in those functions, we use the GRANT
+-- system to REVOKE access to those functions at initdb time.  Administrators
+-- can later change who can access these functions, or leave them as only
+-- available to superuser / cluster owner, if they choose.
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_switch_xlog() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_pause() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_resume() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_rotate_logfile() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public;
+
+REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_table_counters(oid) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM public;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 1467355..41f4374 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -1217,6 +1217,9 @@ pgstat_drop_relation(Oid relid)
  * pgstat_reset_counters() -
  *
  *	Tell the statistics collector to reset counters for our database.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1227,11 +1230,6 @@ pgstat_reset_counters(void)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETCOUNTER);
 	msg.m_databaseid = MyDatabaseId;
 	pgstat_send(&msg, sizeof(msg));
@@ -1241,6 +1239,9 @@ pgstat_reset_counters(void)
  * pgstat_reset_shared_counters() -
  *
  *	Tell the statistics collector to reset cluster-wide shared counters.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1251,11 +1252,6 @@ pgstat_reset_shared_counters(const char *target)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	if (strcmp(target, "archiver") == 0)
 		msg.m_resettarget = RESET_ARCHIVER;
 	else if (strcmp(target, "bgwriter") == 0)
@@ -1274,6 +1270,9 @@ pgstat_reset_shared_counters(const char *target)
  * pgstat_reset_single_counter() -
  *
  *	Tell the statistics collector to reset a single counter.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1284,11 +1283,6 @@ pgstat_reset_single_counter(Oid objoid, PgStat_Single_Reset_Type type)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSINGLECOUNTER);
 	msg.m_databaseid = MyDatabaseId;
 	msg.m_resettype = type;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 4dcc5a6..01e25ff 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -321,15 +321,13 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
 
 /*
  * Signal to reload the database configuration
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_reload_conf(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to signal the postmaster"))));
-
 	if (kill(PostmasterPid, SIGHUP))
 	{
 		ereport(WARNING,
@@ -343,15 +341,13 @@ pg_reload_conf(PG_FUNCTION_ARGS)
 
 /*
  * Rotate log file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_rotate_logfile(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to rotate log files"))));
-
 	if (!Logging_collector)
 	{
 		ereport(WARNING,
-- 
2.5.0

#4Jose Luis Tallon
jltallon@adv-solutions.net
In reply to: Stephen Frost (#3)

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: tested, passed

Patch does not apply cleanly (via "git am") as of today's master; but does apply with "patch"; minor fuzzes apart, so tested with that.
The functionality contained in this patch was badly needed: IMHO, it is a BUG that we do not *perfectly* restore (even when it's only default and catalog/extensions)

DESIGN/DOCUMENTATION
* int4 for the "objsubid" field? and int2 would surely suffice, given that we only allow up to 1600 columns ... if it's a matter of alignment, it would be interesting to say so somewhere (code comments, maybe?)
* Initial ACL preservation:
" * Note that any initial ACLs (see pg_init_privs) will be removed when we
* extract the information about the object. We don't provide support for
* initial policies and security labels and it seems unlikely for those
* to ever exist, but we may have to revisit this later.
" ... fair enough, but it ought to be documented in the manual, too. IMO.

DOCUMENTATION
- Under "privtype" it says: "A code defining the type of initial privilege of this object; see text" ... but the patch doesn't seem to contain the referenced text¿?
A minor omission, definitively --- it is indeed easily derived from enum InitPrivsType's definition at include/catalog/pg_init_privs.h

CODE
"#if ACLDEBUG" code blocks are still present; should be removed before commiting
(I quite like the DumpComponents typedef vs bool [previous], BTW; Clean, readable and effective)

Code comments are descriptive enough and generally properly spellt.
Exception: src/bin/pg_dump/dumputils.c: s/privilegs/privileges/ (line 132)

Minor issue: diff size could have been really reduced by omitting the extra indent after the newly-included checks for "dumping required"
(i.e. not indent the dumpXXX after the "if ( yyy->dobj.dump & ... )"
After all, pgindent will take care of tabs before release :)

Within buildACLCommands(), multiple ocurrences of strncmp( ... ,"group ", strlen("group ") could have been avoided, but code simplicity/readability could be affected
... whereas in other places one reads "if( strncmp(nsinfo->dobj.name, "pg_catalog", 10) == 0) "

I think it is debatable whether DumpOptions belong inside Archive or not (I would have kept it separate, FWIW), but that is unrelated to the correctness of this patch.

Code builds, installs and "make check"s ok.

TESTING:
- pg_dumpall properly dumps the REVOKE statements to store the ACL changes to catalog objects
- pg_init_privs records all initial privileges on objects (from initdb time)
- "psql -f" re-creates all privileges

The new status of this patch is: Ready for Committer

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Robert Haas
robertmhaas@gmail.com
In reply to: Jose Luis Tallon (#4)

On Wed, Mar 30, 2016 at 1:35 PM, Jose Luis Tallon
<jltallon@adv-solutions.net> wrote:

DESIGN/DOCUMENTATION
* int4 for the "objsubid" field? and int2 would surely suffice, given that we only allow up to 1600 columns ... if it's a matter of alignment, it would be interesting to say so somewhere (code comments, maybe?)

There is a lot of existing precedent for objsubid being int4, and
basically no advantage to making it int2.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Stephen Frost
sfrost@snowman.net
In reply to: Jose Luis Tallon (#4)
1 attachment(s)

Jose,

* Jose Luis Tallon (jltallon@adv-solutions.net) wrote:

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: tested, passed

Thanks for the review!

Patch does not apply cleanly (via "git am") as of today's master; but does apply with "patch"; minor fuzzes apart, so tested with that.

Just needed to be rebased and then updated to reflect the additions of
dumping the access methods to pg_dump. Updated patch series attached.

The functionality contained in this patch was badly needed: IMHO, it is a BUG that we do not *perfectly* restore (even when it's only default and catalog/extensions)

Guess I have to agree with that. :)

DESIGN/DOCUMENTATION
* int4 for the "objsubid" field? and int2 would surely suffice, given that we only allow up to 1600 columns ... if it's a matter of alignment, it would be interesting to say so somewhere (code comments, maybe?)

As Robert noted, this is a long-standing convention and is used
throughout our existing code-base. It's certainly not the purview of
this particular patch to change that.

* Initial ACL preservation:
" * Note that any initial ACLs (see pg_init_privs) will be removed when we
* extract the information about the object. We don't provide support for
* initial policies and security labels and it seems unlikely for those
* to ever exist, but we may have to revisit this later.
" ... fair enough, but it ought to be documented in the manual, too. IMO.

Fixed.

DOCUMENTATION
- Under "privtype" it says: "A code defining the type of initial privilege of this object; see text" ... but the patch doesn't seem to contain the referenced text¿?
A minor omission, definitively --- it is indeed easily derived from enum InitPrivsType's definition at include/catalog/pg_init_privs.h

Fixed.

CODE
"#if ACLDEBUG" code blocks are still present; should be removed before commiting
(I quite like the DumpComponents typedef vs bool [previous], BTW; Clean, readable and effective)

The '#if ACLDEBUG's are not from this patch-set and I don't think it's
this patch's job to remove them ...

Code comments are descriptive enough and generally properly spellt.
Exception: src/bin/pg_dump/dumputils.c: s/privilegs/privileges/ (line 132)

Fixed.

Minor issue: diff size could have been really reduced by omitting the extra indent after the newly-included checks for "dumping required"
(i.e. not indent the dumpXXX after the "if ( yyy->dobj.dump & ... )"
After all, pgindent will take care of tabs before release :)

Fixed as best as I could, pgindent is pretty clean for the changes which
this patch set introduces (note that other patches have been committed
which are not pgindent clean and therefore certain files will still be
changed on the next pgindent run, such as pg_dump.c).

Within buildACLCommands(), multiple ocurrences of strncmp( ... ,"group ", strlen("group ") could have been avoided, but code simplicity/readability could be affected
... whereas in other places one reads "if( strncmp(nsinfo->dobj.name, "pg_catalog", 10) == 0) "

Fixed by doing 'strlen("pg_catalog")' in the one spot which had been
using a hard-coded value of '10'.

I think it is debatable whether DumpOptions belong inside Archive or not (I would have kept it separate, FWIW), but that is unrelated to the correctness of this patch.

I didn't see the sense of changing that as part of this patch.

Code builds, installs and "make check"s ok.

TESTING:
- pg_dumpall properly dumps the REVOKE statements to store the ACL changes to catalog objects
- pg_init_privs records all initial privileges on objects (from initdb time)
- "psql -f" re-creates all privileges

The new status of this patch is: Ready for Committer

Very cool.

Thanks again for the review!

I invite others to take a look at the new catalog ('pg_init_privs') and
the changes made to pg_dump and voice any concerns or opinions regarding
those or anything else in this patch set as I've now been through it
again, cleaned up and added more comments, cleaned up and added more to
the documentation, even found a couple bugs which I fixed (particularly
around populating pg_init_privs for columns, and in buildACLCommands()
in pg_dump which is a bit tricky, but now has a lot more comments) and
generally am feeling pretty happy about this patch set.

Barring objections, I'm planning to push this in the next few days.

Thanks!

Stephen

Attachments:

catalog_acls_v6.patchtext/x-diff; charset=us-asciiDownload
From 5fa3860b0413345ccd007ba5ecb26695404b0eb8 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Thu, 10 Mar 2016 20:56:09 -0500
Subject: [PATCH 1/5] Add new catalog called pg_init_privs

This new catalog holds the privileges which the system was
initialized with at initdb time, along with any permissions set
by extensions at CREATE EXTENSION time.  This allows pg_dump
(and any other similar use-cases) to detect when the privileges
set on initdb-created or extension-created objects have been
changed from what they were set to at initdb/extension-creation
time and handle those changes appropriately.
---
 doc/src/sgml/catalogs.sgml                 | 108 +++++++++++++++++++++
 src/backend/catalog/Makefile               |   2 +-
 src/backend/catalog/aclchk.c               | 149 +++++++++++++++++++++++++++++
 src/backend/catalog/dependency.c           |  46 ++++++++-
 src/bin/initdb/initdb.c                    | 143 +++++++++++++++++++++++++++
 src/include/catalog/indexing.h             |   3 +
 src/include/catalog/pg_init_privs.h        | 101 +++++++++++++++++++
 src/test/regress/expected/sanity_check.out |   1 +
 8 files changed, 549 insertions(+), 4 deletions(-)
 create mode 100644 src/include/catalog/pg_init_privs.h

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index bb75229..c8897f4 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -179,6 +179,11 @@
      </row>
 
      <row>
+      <entry><link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link></entry>
+      <entry>object initial privileges</entry>
+     </row>
+
+     <row>
       <entry><link linkend="catalog-pg-language"><structname>pg_language</structname></link></entry>
       <entry>languages for writing functions</entry>
      </row>
@@ -3772,6 +3777,109 @@
 
  </sect1>
 
+ <sect1 id="catalog-pg-init-privs">
+  <title><structname>pg_init_privs</structname></title>
+
+  <indexterm zone="catalog-pg-init-privs">
+   <primary>pg_init_privs</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_init_privs</> records information about
+   the initial privileges of objects in the system.  There is one entry
+   for each object in the database which has a non-default (non-NULL)
+   initial set of privileges.
+  </para>
+
+  <para>
+   Objects can have initial privileges either by having those privileges set
+   when the system is initialized (by <application>initdb</>) or when the
+   object is created during a <command>CREATE EXTENSION</command> and the
+   extension script sets initial privileges using the <command>GRANT</command>
+   system.  Note that the system will automatically handle recording of the
+   privileges during the extension script and that extension authors need
+   only use the <command>GRANT</command> and <command>REVOKE</command>
+   statements in their script to have the privileges recorded.  The
+   <literal>privtype</literal> column indicates if the initial privilege was
+   set by <application>initdb</> or during a
+   <command>CREATE EXTENSION</command> command.
+  </para>
+
+  <para>
+   Objects which have initial privileges set by <application>initdb</> will
+   have entries where <literal>privtype</literal> is
+   <literal>'i'</literal>, while objects which have initial privileges set
+   by <command>CREATE EXTENSION</command> will have entries where
+   <literal>privtype</literal> is <literal>'e'</literal>.
+  </para>
+
+  <table>
+   <title><structname>pg_inherits</> Columns</title>
+
+   <tgroup cols="4">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>objoid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry>any OID column</entry>
+      <entry>The OID of the specific object</entry>
+     </row>
+
+     <row>
+      <entry><structfield>classoid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
+      <entry>The OID of the system catalog the object is in</entry>
+     </row>
+
+     <row>
+      <entry><structfield>objsubid</structfield></entry>
+      <entry><type>int4</type></entry>
+      <entry></entry>
+      <entry>
+       For a table column, this is the column number (the
+       <structfield>objoid</> and <structfield>classoid</> refer to the
+       table itself).  For all other object types, this column is
+       zero.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>privtype</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>
+       A code defining the type of initial privilege of this object; see text
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>initprivs</structfield></entry>
+      <entry><type>aclitem[]</type></entry>
+      <entry></entry>
+      <entry>
+       The initial access privileges; see
+       <xref linkend="sql-grant"> and
+       <xref linkend="sql-revoke">
+       for details
+      </entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
 
  <sect1 id="catalog-pg-language">
   <title><structname>pg_language</structname></title>
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 25130ec..1ce7610 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -40,7 +40,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_ts_parser.h pg_ts_template.h pg_extension.h \
 	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
 	pg_foreign_table.h pg_policy.h pg_replication_origin.h \
-	pg_default_acl.h pg_seclabel.h pg_shseclabel.h \
+	pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
 	pg_collation.h pg_range.h pg_transform.h \
 	toasting.h indexing.h \
     )
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 0f3bc07..ffb6678 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_extension.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
+#include "catalog/pg_init_privs.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_largeobject_metadata.h"
@@ -49,6 +50,7 @@
 #include "catalog/pg_ts_dict.h"
 #include "commands/dbcommands.h"
 #include "commands/event_trigger.h"
+#include "commands/extension.h"
 #include "commands/proclang.h"
 #include "commands/tablespace.h"
 #include "foreign/foreign.h"
@@ -119,6 +121,8 @@ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
 						 AttrNumber att_number, const char *colname);
 static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
 		   Oid roleid, AclMode mask, AclMaskHow how);
+static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
+						Acl *new_acl);
 
 
 #ifdef ACLDEBUG
@@ -1678,6 +1682,10 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(attRelation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(relOid, RelationRelationId, attnum,
+								ACL_NUM(new_acl) > 0 ? new_acl : NULL);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(RelationRelationId, relOid, attnum,
 							  ownerId,
@@ -1939,6 +1947,9 @@ ExecGrant_Relation(InternalGrant *istmt)
 			/* keep the catalog indexes up to date */
 			CatalogUpdateIndexes(relation, newtuple);
 
+			/* Update initial privileges for extensions */
+			recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
+
 			/* Update the shared dependency ACL info */
 			updateAclDependencies(RelationRelationId, relOid, 0,
 								  ownerId,
@@ -2254,6 +2265,10 @@ ExecGrant_Fdw(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
+								new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ForeignDataWrapperRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2379,6 +2394,9 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ForeignServerRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2503,6 +2521,9 @@ ExecGrant_Function(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ProcedureRelationId, funcId, 0,
 							  ownerId,
@@ -2633,6 +2654,9 @@ ExecGrant_Language(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
 							  ownerId,
@@ -2772,6 +2796,9 @@ ExecGrant_Largeobject(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(LargeObjectRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2897,6 +2924,9 @@ ExecGrant_Namespace(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
 							  ownerId,
@@ -3158,6 +3188,9 @@ ExecGrant_Type(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(TypeRelationId, typId, 0,
 							  ownerId,
@@ -5174,3 +5207,119 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
 
 	return result;
 }
+
+/*
+ * Record initial ACL for an extension object
+ *
+ * This will perform a wholesale replacement of the entire ACL for the object
+ * passed in, therefore be sure to pass in the complete new ACL to use.
+ *
+ * Can be called at any time, we check if 'creating_extension' is set and, if
+ * not, exit immediately.
+ *
+ * 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.
+ *
+ * If an ACL already exists for this object/sub-object then we will replace
+ * it with what is passed in.
+ *
+ * Passing in NULL for 'new_acl' will result in the entry for the object being
+ * removed, if one is found.
+ */
+static void
+recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
+{
+	Relation	relation;
+	ScanKeyData key[3];
+	SysScanDesc scan;
+	HeapTuple	tuple;
+	HeapTuple	oldtuple;
+
+	if (!creating_extension)
+		return;
+
+	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_init_privs_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(objoid));
+	ScanKeyInit(&key[1],
+				Anum_pg_init_privs_classoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(classoid));
+	ScanKeyInit(&key[2],
+				Anum_pg_init_privs_objsubid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(objsubid));
+
+	scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
+							  NULL, 3, key);
+
+	/* There should exist only one entry or none. */
+	oldtuple = systable_getnext(scan);
+
+	systable_endscan(scan);
+
+	/* If we find an entry, update it with the latest ACL. */
+	if (HeapTupleIsValid(oldtuple))
+	{
+		Datum		values[Natts_pg_init_privs];
+		bool		nulls[Natts_pg_init_privs];
+		bool		replace[Natts_pg_init_privs];
+
+		/* If we have a new ACL to set, then update the row with it. */
+		if (new_acl)
+		{
+			MemSet(values, 0, sizeof(values));
+			MemSet(nulls, false, sizeof(nulls));
+			MemSet(replace, false, sizeof(replace));
+
+			values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
+			replace[Anum_pg_init_privs_privs - 1] = true;
+
+			oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
+										 values, nulls, replace);
+
+			simple_heap_update(relation, &oldtuple->t_self, oldtuple);
+
+			/* keep the catalog indexes up to date */
+			CatalogUpdateIndexes(relation, oldtuple);
+		}
+		else
+			/* new_acl is NULL, so delete the entry we found. */
+			simple_heap_delete(relation, &oldtuple->t_self);
+	}
+	else
+	{
+		/* No entry found, so add it. */
+		Datum		values[Natts_pg_init_privs];
+		bool		nulls[Natts_pg_init_privs];
+
+		MemSet(nulls, false, sizeof(nulls));
+
+		values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
+		values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
+		values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
+
+		/* This function only handles initial privileges of extensions */
+		values[Anum_pg_init_privs_privtype - 1] =
+			CharGetDatum(INITPRIVS_EXTENSION);
+
+		values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
+
+		tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
+
+		simple_heap_insert(relation, tuple);
+
+		/* keep the catalog indexes up to date */
+		CatalogUpdateIndexes(relation, tuple);
+	}
+
+	/* prevent error when processing objects multiple times */
+	CommandCounterIncrement();
+
+	heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 17f9de1..400cb9f 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -39,6 +39,7 @@
 #include "catalog/pg_extension.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
+#include "catalog/pg_init_privs.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_namespace.h"
@@ -196,6 +197,7 @@ static bool object_address_present_add_flags(const ObjectAddress *object,
 static bool stack_address_present_add_flags(const ObjectAddress *object,
 								int flags,
 								ObjectAddressStack *stack);
+static void DeleteInitPrivs(const ObjectAddress *object);
 
 
 /*
@@ -1104,12 +1106,13 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
 
 
 	/*
-	 * Delete any comments or security labels associated with this object.
-	 * (This is a convenient place to do these things, rather than having
-	 * every object type know to do it.)
+	 * Delete any comments, security labels, or initial privileges associated
+	 * with this object.  (This is a convenient place to do these things,
+	 * rather than having every object type know to do it.)
 	 */
 	DeleteComments(object->objectId, object->classId, object->objectSubId);
 	DeleteSecurityLabel(object);
+	DeleteInitPrivs(object);
 
 	/*
 	 * CommandCounterIncrement here to ensure that preceding changes are all
@@ -2430,3 +2433,40 @@ getObjectClass(const ObjectAddress *object)
 	elog(ERROR, "unrecognized object class: %u", object->classId);
 	return OCLASS_CLASS;		/* keep compiler quiet */
 }
+
+/*
+ * delete initial ACL for extension objects
+ */
+static void
+DeleteInitPrivs(const ObjectAddress *object)
+{
+	Relation	relation;
+	ScanKeyData key[3];
+	SysScanDesc scan;
+	HeapTuple	oldtuple;
+
+	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_init_privs_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->objectId));
+	ScanKeyInit(&key[1],
+				Anum_pg_init_privs_classoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->classId));
+	ScanKeyInit(&key[2],
+				Anum_pg_init_privs_objsubid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(object->objectSubId));
+
+	scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
+							  NULL, 3, key);
+
+	while (HeapTupleIsValid(oldtuple = systable_getnext(scan)))
+		simple_heap_delete(relation, &oldtuple->t_self);
+
+	systable_endscan(scan);
+
+	heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index ed3ba7b..858667b 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1989,6 +1989,11 @@ setup_dictionary(FILE *cmdfd)
  * Some objects may require different permissions by default, so we
  * make sure we don't overwrite privilege sets that have already been
  * set (NOT NULL).
+ *
+ * Also populate pg_init_privs to save what the privileges are at init
+ * time.  This is used by pg_dump to allow users to change privileges
+ * on catalog objects and to have those privilege changes preserved
+ * across dump/reload and pg_upgrade.
  */
 static void
 setup_privileges(FILE *cmdfd)
@@ -2002,6 +2007,144 @@ setup_privileges(FILE *cmdfd)
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
 		"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        0,"
+		"        relacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_class"
+		"    WHERE"
+		"        relacl IS NOT NULL"
+		"        AND relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        pg_class.oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        pg_attribute.attnum,"
+		"        pg_attribute.attacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_class"
+		"        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
+		"    WHERE"
+		"        pg_attribute.attacl IS NOT NULL"
+		"        AND pg_class.relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),"
+		"        0,"
+		"        proacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_proc"
+		"    WHERE"
+		"        proacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_type'),"
+		"        0,"
+		"        typacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_type"
+		"    WHERE"
+		"        typacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_language'),"
+		"        0,"
+		"        lanacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_language"
+		"    WHERE"
+		"        lanacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_largeobject_metadata'),"
+		"        0,"
+		"        lomacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_largeobject_metadata"
+		"    WHERE"
+		"        lomacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),"
+		"        0,"
+		"        nspacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_namespace"
+		"    WHERE"
+		"        nspacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_database'),"
+		"        0,"
+		"        datacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_database"
+		"    WHERE"
+		"        datacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_tablespace'),"
+		"        0,"
+		"        spcacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_tablespace"
+		"    WHERE"
+		"        spcacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_foreign_data_wrapper'),"
+		"        0,"
+		"        fdwacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_foreign_data_wrapper"
+		"    WHERE"
+		"        fdwacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class "
+		"		  WHERE relname = 'pg_foreign_server'),"
+		"        0,"
+		"        srvacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_foreign_server"
+		"    WHERE"
+		"        srvacl IS NOT NULL;",
 		NULL
 	};
 
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index ab2c1a8..1a94f6d 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -162,6 +162,9 @@ DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using b
 DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhparent oid_ops));
 #define InheritsParentIndexId  2187
 
+DECLARE_UNIQUE_INDEX(pg_init_privs_o_c_o_index, 2740, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
+#define InitPrivsObjIndexId  2740
+
 DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops));
 #define LanguageNameIndexId  2681
 DECLARE_UNIQUE_INDEX(pg_language_oid_index, 2682, on pg_language using btree(oid oid_ops));
diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h
new file mode 100644
index 0000000..39267d1
--- /dev/null
+++ b/src/include/catalog/pg_init_privs.h
@@ -0,0 +1,101 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_init_privs.h
+ *	  definition of the system "initial privileges" relation (pg_init_privs)
+ *
+ * NOTE: an object is identified by the OID of the row that primarily
+ * defines the object, plus the OID of the table that that row appears in.
+ * For example, a function is identified by the OID of its pg_proc row
+ * plus the pg_class OID of table pg_proc.  This allows unique identification
+ * of objects without assuming that OIDs are unique across tables.
+ *
+ * Since attributes don't have OIDs of their own, we identify an attribute
+ * privilege by the objoid+classoid of its parent table, plus an "objsubid"
+ * giving the attribute column number.  "objsubid" must be zero in a privilege
+ * for a table itself, so that it is distinct from any column privilege.
+ * Currently, objsubid is unused and zero for all other kinds of objects.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_init_privs.h
+ *
+ * NOTES
+ *		the genbki.pl script reads this file and generates .bki
+ *		information from the DATA() statements.
+ *
+ *		XXX do NOT break up DATA() statements into multiple lines!
+ *			the scripts are not as smart as you might think...
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_INIT_PRIVS_H
+#define PG_INIT_PRIVS_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ *		pg_init_privs definition.  cpp turns this into
+ *		typedef struct FormData_pg_init_privs
+ * ----------------
+ */
+#define InitPrivsRelationId  2739
+
+CATALOG(pg_init_privs,2739) BKI_WITHOUT_OIDS
+{
+	Oid			objoid;			/* OID of object itself */
+	Oid			classoid;		/* OID of table containing object */
+	int32		objsubid;		/* column number, or 0 if not used */
+	char		privtype;		/* from initdb or extension? */
+
+#ifdef CATALOG_VARLEN			/* variable-length fields start here */
+	aclitem		initprivs[1] BKI_FORCE_NOT_NULL;		/* initial privs on
+														 * object */
+#endif
+} FormData_pg_init_privs;
+
+/* ----------------
+ *		Form_pg_init_privs corresponds to a pointer to a tuple with
+ *		the format of pg_init_privs relation.
+ * ----------------
+ */
+typedef FormData_pg_init_privs *Form_pg_init_privs;
+
+/* ----------------
+ *		compiler constants for pg_init_privs
+ * ----------------
+ */
+#define Natts_pg_init_privs				5
+#define Anum_pg_init_privs_objoid		1
+#define Anum_pg_init_privs_classoid		2
+#define Anum_pg_init_privs_objsubid		3
+#define Anum_pg_init_privs_privtype		4
+#define Anum_pg_init_privs_privs		5
+
+/*
+ * It is important to know if the initial privileges are from initdb or from an
+ * extension.  This enum is used to provide that differentiation and the two
+ * places which populate this table (initdb and during CREATE EXTENSION, see
+ * recordExtensionInitPriv()) know to use the correct values.
+ */
+
+typedef enum InitPrivsType
+{
+	INITPRIVS_INITDB = 'i',
+	INITPRIVS_EXTENSION = 'e'
+} InitPrivsType;
+
+/* ----------------
+ *		initial contents of pg_init_privs
+ * ----------------
+ */
+
+/*
+ *	Because the contents of this table depend on what is done with the other
+ *	objects in the system (and, in particular, may change due to changes is
+ *	system_views.sql), there is no initialization here.
+ *
+ *	The initial contents are loaded near the end of initdb.
+ */
+
+#endif   /* PG_INIT_PRIVS_H */
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 2c5be4b..4d81ba7 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -110,6 +110,7 @@ pg_foreign_server|t
 pg_foreign_table|t
 pg_index|t
 pg_inherits|t
+pg_init_privs|t
 pg_language|t
 pg_largeobject|t
 pg_largeobject_metadata|t
-- 
2.5.0


From 34b2d1820801a45de0c229a329b9ae90bc894ccc Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:31:03 -0400
Subject: [PATCH 2/5] In pg_dump, use a bitmap to represent what to include

pg_dump has historically used a simple boolean 'dump' value to indicate
if a given object should be included in the dump or not.  Instead, use
a bitmap which breaks down the components of an object into their
distinct pieces and use that bitmap to only include the components
requested.

This does not include any behavioral change, but is in preperation for
the change to dump out just ACLs for objects in pg_catalog.
---
 src/bin/pg_dump/common.c  |    2 +-
 src/bin/pg_dump/pg_dump.c | 1502 ++++++++++++++++++++++++---------------------
 src/bin/pg_dump/pg_dump.h |   14 +-
 3 files changed, 833 insertions(+), 685 deletions(-)

diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 373d3bc..1cbb987 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -443,7 +443,7 @@ AssignDumpId(DumpableObject *dobj)
 	dobj->dumpId = ++lastDumpId;
 	dobj->name = NULL;			/* must be set later */
 	dobj->namespace = NULL;		/* may be set later */
-	dobj->dump = true;			/* default assumption */
+	dobj->dump = DUMP_COMPONENT_ALL;	/* default assumption */
 	dobj->ext_member = false;	/* default assumption */
 	dobj->dependencies = NULL;
 	dobj->nDeps = 0;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 454225d..5fa9992 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1287,7 +1287,7 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
 	 * extension contents with something different.
 	 */
 	if (!dopt->binary_upgrade)
-		dobj->dump = false;
+		dobj->dump = DUMP_COMPONENT_NONE;
 	else
 		dobj->dump = ext->dobj.dump;
 
@@ -1309,16 +1309,18 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 * namespaces. If specific namespaces are being dumped, dump just those
 	 * namespaces. Otherwise, dump all non-system namespaces.
 	 */
+
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
 		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
-												   nsinfo->dobj.catId.oid);
+								   nsinfo->dobj.catId.oid) ?
+							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = true;
+		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
@@ -1326,7 +1328,7 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	if (nsinfo->dobj.dump &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1345,7 +1347,8 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	 */
 	if (table_include_oids.head != NULL)
 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
-												   tbinfo->dobj.catId.oid);
+												   tbinfo->dobj.catId.oid) ?
+								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
 
@@ -1355,7 +1358,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	if (tbinfo->dobj.dump &&
 		simple_oid_list_member(&table_exclude_oids,
 							   tbinfo->dobj.catId.oid))
-		tbinfo->dobj.dump = false;
+		tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1384,7 +1387,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 		if (tytable != NULL)
 			tyinfo->dobj.dump = tytable->dobj.dump;
 		else
-			tyinfo->dobj.dump = false;
+			tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
 		return;
 	}
 
@@ -1404,11 +1407,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	/* dump only types in dumpable namespaces */
-	if (!tyinfo->dobj.namespace->dobj.dump)
-		tyinfo->dobj.dump = false;
-	else
-		tyinfo->dobj.dump = true;
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
 }
 
 /*
@@ -1427,7 +1426,8 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	if (dinfo->dobj.namespace)
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
-		dinfo->dobj.dump = dopt->include_everything;
+		dinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1446,9 +1446,10 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		cast->dobj.dump = false;
+		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		cast->dobj.dump = dopt->include_everything;
+		cast->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1466,9 +1467,10 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		plang->dobj.dump = false;
+		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = dopt->include_everything;
+		plang->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1505,9 +1507,10 @@ static void
 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 {
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = false;
+		extinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		extinfo->dobj.dump = dopt->include_everything;
+		extinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1529,7 +1532,8 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	if (dobj->namespace)
 		dobj->dump = dobj->namespace->dobj.dump;
 	else
-		dobj->dump = dopt->include_everything;
+		dobj->dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1934,13 +1938,14 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
 	 * dependency on its table as "special" and pass it to ArchiveEntry now.
 	 * See comments for BuildArchiveDependencies.
 	 */
-	ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
-				 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
-				 NULL, tbinfo->rolname,
-				 false, "TABLE DATA", SECTION_DATA,
-				 "", "", copyStmt,
-				 &(tbinfo->dobj.dumpId), 1,
-				 dumpFn, tdinfo);
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
+					 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
+					 NULL, tbinfo->rolname,
+					 false, "TABLE DATA", SECTION_DATA,
+					 "", "", copyStmt,
+					 &(tbinfo->dobj.dumpId), 1,
+					 dumpFn, tdinfo);
 
 	destroyPQExpBuffer(copyBuf);
 	destroyPQExpBuffer(clistBuf);
@@ -1968,23 +1973,24 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout,
-				 tdinfo->dobj.catId,	/* catalog ID */
-				 tdinfo->dobj.dumpId,	/* dump ID */
-				 tbinfo->dobj.name,		/* Name */
-				 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
-				 NULL,			/* Tablespace */
-				 tbinfo->rolname,		/* Owner */
-				 false,			/* with oids */
-				 "MATERIALIZED VIEW DATA",		/* Desc */
-				 SECTION_POST_DATA,		/* Section */
-				 q->data,		/* Create */
-				 "",			/* Del */
-				 NULL,			/* Copy */
-				 tdinfo->dobj.dependencies,		/* Deps */
-				 tdinfo->dobj.nDeps,	/* # Deps */
-				 NULL,			/* Dumper */
-				 NULL);			/* Dumper Arg */
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout,
+					 tdinfo->dobj.catId,	/* catalog ID */
+					 tdinfo->dobj.dumpId,	/* dump ID */
+					 tbinfo->dobj.name,		/* Name */
+					 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
+					 NULL,			/* Tablespace */
+					 tbinfo->rolname,		/* Owner */
+					 false,			/* with oids */
+					 "MATERIALIZED VIEW DATA",		/* Desc */
+					 SECTION_POST_DATA,		/* Section */
+					 q->data,		/* Create */
+					 "",			/* Del */
+					 NULL,			/* Copy */
+					 tdinfo->dobj.dependencies,		/* Deps */
+					 tdinfo->dobj.nDeps,	/* # Deps */
+					 NULL,			/* Dumper */
+					 NULL);			/* Dumper Arg */
 
 	destroyPQExpBuffer(q);
 }
@@ -2000,7 +2006,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids)
 
 	for (i = 0; i < numTables; i++)
 	{
-		if (tblinfo[i].dobj.dump)
+		if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA)
 			makeTableDataInfo(dopt, &(tblinfo[i]), oids);
 	}
 }
@@ -2261,7 +2267,7 @@ guessConstraintInheritance(TableInfo *tblinfo, int numTables)
 			continue;
 
 		/* Don't bother computing anything for non-target tables, either */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		numParents = tbinfo->numParents;
@@ -2811,31 +2817,34 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 					  "SELECT pg_catalog.lo_unlink('%s');\n",
 					  binfo->dobj.name);
 
-	ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
-				 binfo->dobj.name,
-				 NULL, NULL,
-				 binfo->rolname, false,
-				 "BLOB", SECTION_PRE_DATA,
-				 cquery->data, dquery->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
+					 binfo->dobj.name,
+					 NULL, NULL,
+					 binfo->rolname, false,
+					 "BLOB", SECTION_PRE_DATA,
+					 cquery->data, dquery->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* set up tag for comment and/or ACL */
 	resetPQExpBuffer(cquery);
 	appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
 
 	/* Dump comment if any */
-	dumpComment(fout, cquery->data,
-				NULL, binfo->rolname,
-				binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, cquery->data,
+					NULL, binfo->rolname,
+					binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump security label if any */
-	dumpSecLabel(fout, cquery->data,
-				 NULL, binfo->rolname,
-				 binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, cquery->data,
+					 NULL, binfo->rolname,
+					 binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump ACL if any */
-	if (binfo->blobacl)
+	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
 		dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 				binfo->dobj.name, NULL, cquery->data,
 				NULL, binfo->rolname, binfo->blobacl);
@@ -2956,7 +2965,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
 		TableInfo  *tbinfo = &tblinfo[i];
 
 		/* Ignore row security on tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
 			continue;
 
 		if (g_verbose)
@@ -3096,15 +3105,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 		appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
 						  fmtId(polinfo->dobj.name));
 
-		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-					 polinfo->dobj.name,
-					 polinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "ROW SECURITY", SECTION_POST_DATA,
-					 query->data, "", NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+			ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+						 polinfo->dobj.name,
+						 polinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "ROW SECURITY", SECTION_POST_DATA,
+						 query->data, "", NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
 		destroyPQExpBuffer(query);
 		return;
@@ -3147,15 +3157,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 	appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
 	appendPQExpBuffer(delqry, " ON %s;\n", fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-				 polinfo->dobj.name,
-				 polinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "POLICY", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+					 polinfo->dobj.name,
+					 polinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "POLICY", SECTION_POST_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -3760,7 +3771,8 @@ getTypes(Archive *fout, int *numTypes)
 		 */
 		tyinfo[i].nDomChecks = 0;
 		tyinfo[i].domChecks = NULL;
-		if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			tyinfo[i].typtype == TYPTYPE_DOMAIN)
 			getDomainConstraints(fout, &(tyinfo[i]));
 
 		/*
@@ -3773,8 +3785,9 @@ getTypes(Archive *fout, int *numTypes)
 		 * should copy the base type's catId, but then it might capture the
 		 * pg_depend entries for the type, which we don't want.
 		 */
-		if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
-									tyinfo[i].typtype == TYPTYPE_RANGE))
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			(tyinfo[i].typtype == TYPTYPE_BASE ||
+			 tyinfo[i].typtype == TYPTYPE_RANGE))
 		{
 			stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
 			stinfo->dobj.objType = DO_SHELL_TYPE;
@@ -3790,7 +3803,7 @@ getTypes(Archive *fout, int *numTypes)
 			 * dump it if the I/O or canonicalize functions need to be dumped;
 			 * this is taken care of while sorting dependencies.
 			 */
-			stinfo->dobj.dump = false;
+			stinfo->dobj.dump = DUMP_COMPONENT_NONE;
 
 			/*
 			 * However, if dumping from pre-7.3, there will be no dependency
@@ -3808,7 +3821,7 @@ getTypes(Archive *fout, int *numTypes)
 				typoutput = atooid(PQgetvalue(res, i, i_typoutput));
 
 				funcInfo = findFuncByOid(typinput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3817,11 +3830,11 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 
 				funcInfo = findFuncByOid(typoutput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3830,7 +3843,7 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 			}
 		}
@@ -5353,10 +5366,11 @@ getTables(Archive *fout, int *numTables)
 		 * Decide whether we want to dump this table.
 		 */
 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
-			tblinfo[i].dobj.dump = false;
+			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
 		else
 			selectDumpableTable(&tblinfo[i], dopt);
-		tblinfo[i].interesting = tblinfo[i].dobj.dump;
+
+		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
 
@@ -5423,13 +5437,13 @@ getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
 
 		if (!OidIsValid(seqinfo->owning_tab))
 			continue;			/* not an owned sequence */
-		if (seqinfo->dobj.dump)
+		if (seqinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			continue;			/* no need to search */
 		owning_tab = findTableByOid(seqinfo->owning_tab);
 		if (owning_tab && owning_tab->dobj.dump)
 		{
 			seqinfo->interesting = true;
-			seqinfo->dobj.dump = true;
+			seqinfo->dobj.dump = DUMP_COMPONENT_ALL;
 		}
 	}
 }
@@ -5531,8 +5545,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 		if (!tbinfo->hasindex)
 			continue;
 
-		/* Ignore indexes of tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		/* Ignore indexes of tables whose definitions are not to be dumped */
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -5899,7 +5913,8 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -6238,7 +6253,8 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -8591,12 +8607,13 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
 			dumpBlob(fout, (BlobInfo *) dobj);
 			break;
 		case DO_BLOB_DATA:
-			ArchiveEntry(fout, dobj->catId, dobj->dumpId,
-						 dobj->name, NULL, NULL, "",
-						 false, "BLOBS", SECTION_DATA,
-						 "", "", NULL,
-						 NULL, 0,
-						 dumpBlobs, NULL);
+			if (dobj->dump & DUMP_COMPONENT_DATA)
+				ArchiveEntry(fout, dobj->catId, dobj->dumpId,
+							 dobj->name, NULL, NULL, "",
+							 false, "BLOBS", SECTION_DATA,
+							 "", "", NULL,
+							 NULL, 0,
+							 dumpBlobs, NULL);
 			break;
 		case DO_POLICY:
 			dumpPolicy(fout, (PolicyInfo *) dobj);
@@ -8644,26 +8661,31 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
-				 nspinfo->dobj.name,
-				 NULL, NULL,
-				 nspinfo->rolname,
-				 false, "SCHEMA", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
+					 nspinfo->dobj.name,
+					 NULL, NULL,
+					 nspinfo->rolname,
+					 false, "SCHEMA", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Schema Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, nspinfo->rolname,
-				nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, nspinfo->rolname,
-				 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, nspinfo->rolname,
+					nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
 
-	dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
-			qnspname, NULL, nspinfo->dobj.name, NULL,
-			nspinfo->rolname, nspinfo->nspacl);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, nspinfo->rolname,
+					 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
+				qnspname, NULL, nspinfo->dobj.name, NULL,
+				nspinfo->rolname, nspinfo->nspacl);
 
 	free(qnspname);
 
@@ -8773,22 +8795,26 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
 	appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
 
-	ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
-				 extinfo->dobj.name,
-				 NULL, NULL,
-				 "",
-				 false, "EXTENSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
+					 extinfo->dobj.name,
+					 NULL, NULL,
+					 "",
+					 false, "EXTENSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Extension Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+
+	if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
 
 	free(qextname);
 
@@ -8928,28 +8954,33 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9061,28 +9092,33 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9131,28 +9167,33 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -9520,28 +9561,33 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9683,28 +9729,33 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "DOMAIN", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "DOMAIN", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Domain Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	/* Dump any per-constraint comments */
 	for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9716,10 +9767,13 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 						  fmtId(domcheck->dobj.name));
 		appendPQExpBuffer(labelq, "ON DOMAIN %s",
 						  qtypname);
-		dumpComment(fout, labelq->data,
-					tyinfo->dobj.namespace->dobj.name,
-					tyinfo->rolname,
-					domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+		if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpComment(fout, labelq->data,
+						tyinfo->dobj.namespace->dobj.name,
+						tyinfo->rolname,
+						domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
 		destroyPQExpBuffer(labelq);
 	}
 
@@ -9909,29 +9963,34 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9941,7 +10000,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	destroyPQExpBuffer(query);
 
 	/* Dump any per-column comments */
-	dumpCompositeTypeColComments(fout, tyinfo);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpCompositeTypeColComments(fout, tyinfo);
 }
 
 /*
@@ -10086,15 +10146,16 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
 					  fmtId(stinfo->dobj.name));
 
-	ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
-				 stinfo->dobj.name,
-				 stinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 stinfo->baseType->rolname, false,
-				 "SHELL TYPE", SECTION_PRE_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
+					 stinfo->dobj.name,
+					 stinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 stinfo->baseType->rolname, false,
+					 "SHELL TYPE", SECTION_PRE_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 }
@@ -10223,23 +10284,27 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
 
-	ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
-				 plang->dobj.name,
-				 lanschema, NULL, plang->lanowner,
-				 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
+					 plang->dobj.name,
+					 lanschema, NULL, plang->lanowner,
+					 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Proc Lang Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				plang->dobj.catId, 0, plang->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 plang->dobj.catId, 0, plang->dobj.dumpId);
+	if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					plang->dobj.catId, 0, plang->dobj.dumpId);
+
+	if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 plang->dobj.catId, 0, plang->dobj.dumpId);
 
-	if (plang->lanpltrusted)
+	if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 				qlanname, NULL, plang->dobj.name,
 				lanschema,
@@ -10888,28 +10953,33 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
-				 funcsig_tag,
-				 finfo->dobj.namespace->dobj.name,
-				 NULL,
-				 finfo->rolname, false,
-				 "FUNCTION", SECTION_PRE_DATA,
-				 q->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
+					 funcsig_tag,
+					 finfo->dobj.namespace->dobj.name,
+					 NULL,
+					 finfo->rolname, false,
+					 "FUNCTION", SECTION_PRE_DATA,
+					 q->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Function Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				finfo->dobj.namespace->dobj.name, finfo->rolname,
-				finfo->dobj.catId, 0, finfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 finfo->dobj.namespace->dobj.name, finfo->rolname,
-				 finfo->dobj.catId, 0, finfo->dobj.dumpId);
+	if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					finfo->dobj.namespace->dobj.name, finfo->rolname,
+					finfo->dobj.catId, 0, finfo->dobj.dumpId);
 
-	dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
-			funcsig, NULL, funcsig_tag,
-			finfo->dobj.namespace->dobj.name,
-			finfo->rolname, finfo->proacl);
+	if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 finfo->dobj.namespace->dobj.name, finfo->rolname,
+					 finfo->dobj.catId, 0, finfo->dobj.dumpId);
+
+	if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
+				funcsig, NULL, funcsig_tag,
+				finfo->dobj.namespace->dobj.name,
+				finfo->rolname, finfo->proacl);
 
 	PQclear(res);
 
@@ -11018,18 +11088,20 @@ dumpCast(Archive *fout, CastInfo *cast)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
 
-	ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "CAST", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "CAST", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Cast Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				cast->dobj.catId, 0, cast->dobj.dumpId);
+	if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					cast->dobj.catId, 0, cast->dobj.dumpId);
 
 	free(sourceType);
 	free(targetType);
@@ -11138,18 +11210,20 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &transform->dobj, labelq->data);
 
-	ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "TRANSFORM", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 transform->dobj.dependencies, transform->dobj.nDeps,
-				 NULL, NULL);
+	if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "TRANSFORM", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 transform->dobj.dependencies, transform->dobj.nDeps,
+					 NULL, NULL);
 
 	/* Dump Transform Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				transform->dobj.catId, 0, transform->dobj.dumpId);
+	if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					transform->dobj.catId, 0, transform->dobj.dumpId);
 
 	free(lanname);
 	free(transformType);
@@ -11392,20 +11466,22 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
-				 oprinfo->dobj.name,
-				 oprinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 oprinfo->rolname,
-				 false, "OPERATOR", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
+					 oprinfo->dobj.name,
+					 oprinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 oprinfo->rolname,
+					 false, "OPERATOR", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Comments */
-	dumpComment(fout, labelq->data,
-				oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
-				oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
+					oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -11970,20 +12046,22 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
-				 opcinfo->dobj.name,
-				 opcinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opcinfo->rolname,
-				 false, "OPERATOR CLASS", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
+					 opcinfo->dobj.name,
+					 opcinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opcinfo->rolname,
+					 false, "OPERATOR CLASS", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Class Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opcinfo->rolname,
-				opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opcinfo->rolname,
+					opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
 
 	free(amname);
 	destroyPQExpBuffer(query);
@@ -12284,20 +12362,22 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
-				 opfinfo->dobj.name,
-				 opfinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opfinfo->rolname,
-				 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
+					 opfinfo->dobj.name,
+					 opfinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opfinfo->rolname,
+					 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Family Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opfinfo->rolname,
-				opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opfinfo->rolname,
+					opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
 
 	free(amname);
 	PQclear(res_ops);
@@ -12374,20 +12454,22 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
-				 collinfo->dobj.name,
-				 collinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 collinfo->rolname,
-				 false, "COLLATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
+					 collinfo->dobj.name,
+					 collinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 collinfo->rolname,
+					 false, "COLLATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Collation Comments */
-	dumpComment(fout, labelq->data,
-				collinfo->dobj.namespace->dobj.name, collinfo->rolname,
-				collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					collinfo->dobj.namespace->dobj.name, collinfo->rolname,
+					collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12474,20 +12556,22 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
-				 convinfo->dobj.name,
-				 convinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 convinfo->rolname,
-				 false, "CONVERSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
+					 convinfo->dobj.name,
+					 convinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 convinfo->rolname,
+					 false, "CONVERSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Conversion Comments */
-	dumpComment(fout, labelq->data,
-				convinfo->dobj.namespace->dobj.name, convinfo->rolname,
-				convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					convinfo->dobj.namespace->dobj.name, convinfo->rolname,
+					convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12937,23 +13021,30 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
 
-	ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-				 aggsig_tag,
-				 agginfo->aggfn.dobj.namespace->dobj.name,
-				 NULL,
-				 agginfo->aggfn.rolname,
-				 false, "AGGREGATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
+					 agginfo->aggfn.dobj.dumpId,
+					 aggsig_tag,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 NULL,
+					 agginfo->aggfn.rolname,
+					 false, "AGGREGATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Aggregate Comments */
-	dumpComment(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					agginfo->aggfn.dobj.namespace->dobj.name,
+					agginfo->aggfn.rolname,
+					agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 agginfo->aggfn.rolname,
+					 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
 	/*
 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
@@ -12966,11 +13057,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	aggsig = format_function_signature(fout, &agginfo->aggfn, true);
 	aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
 
-	dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-			"FUNCTION",
-			aggsig, NULL, aggsig_tag,
-			agginfo->aggfn.dobj.namespace->dobj.name,
-			agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
+				"FUNCTION",
+				aggsig, NULL, aggsig_tag,
+				agginfo->aggfn.dobj.namespace->dobj.name,
+				agginfo->aggfn.rolname, agginfo->aggfn.proacl);
 
 	free(aggsig);
 	if (aggfullsig)
@@ -13038,20 +13130,22 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
-				 prsinfo->dobj.name,
-				 prsinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
+					 prsinfo->dobj.name,
+					 prsinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Parser Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13126,20 +13220,22 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
-				 dictinfo->dobj.name,
-				 dictinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 dictinfo->rolname,
-				 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
+					 dictinfo->dobj.name,
+					 dictinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 dictinfo->rolname,
+					 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Dictionary Comments */
-	dumpComment(fout, labelq->data,
-				NULL, dictinfo->rolname,
-				dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, dictinfo->rolname,
+					dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13193,20 +13289,22 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
-				 tmplinfo->dobj.name,
-				 tmplinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
+					 tmplinfo->dobj.name,
+					 tmplinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Template Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13322,20 +13420,22 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
-				 cfginfo->dobj.name,
-				 cfginfo->dobj.namespace->dobj.name,
-				 NULL,
-				 cfginfo->rolname,
-				 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
+					 cfginfo->dobj.name,
+					 cfginfo->dobj.namespace->dobj.name,
+					 NULL,
+					 cfginfo->rolname,
+					 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Configuration Comments */
-	dumpComment(fout, labelq->data,
-				NULL, cfginfo->rolname,
-				cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, cfginfo->rolname,
+					cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13389,27 +13489,30 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-				 fdwinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 fdwinfo->rolname,
-				 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+					 fdwinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 fdwinfo->rolname,
+					 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-			"FOREIGN DATA WRAPPER",
-			qfdwname, NULL, fdwinfo->dobj.name,
-			NULL, fdwinfo->rolname,
-			fdwinfo->fdwacl);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+				"FOREIGN DATA WRAPPER",
+				qfdwname, NULL, fdwinfo->dobj.name,
+				NULL, fdwinfo->rolname,
+				fdwinfo->fdwacl);
 
 	/* Dump Foreign Data Wrapper Comments */
-	dumpComment(fout, labelq->data,
-				NULL, fdwinfo->rolname,
-				fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, fdwinfo->rolname,
+					fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
 
 	free(qfdwname);
 
@@ -13482,33 +13585,37 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-				 srvinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 srvinfo->rolname,
-				 false, "SERVER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+					 srvinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 srvinfo->rolname,
+					 false, "SERVER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-			"FOREIGN SERVER",
-			qsrvname, NULL, srvinfo->dobj.name,
-			NULL, srvinfo->rolname,
-			srvinfo->srvacl);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+				"FOREIGN SERVER",
+				qsrvname, NULL, srvinfo->dobj.name,
+				NULL, srvinfo->rolname,
+				srvinfo->srvacl);
 
 	/* Dump user mappings */
-	dumpUserMappings(fout,
-					 srvinfo->dobj.name, NULL,
-					 srvinfo->rolname,
-					 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
+		dumpUserMappings(fout,
+						 srvinfo->dobj.name, NULL,
+						 srvinfo->rolname,
+						 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
 
 	/* Dump Foreign Server Comments */
-	dumpComment(fout, labelq->data,
-				NULL, srvinfo->rolname,
-				srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, srvinfo->rolname,
+					srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
 
 	free(qsrvname);
 
@@ -13671,15 +13778,16 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 		exit_horribly(NULL, "could not parse default ACL list (%s)\n",
 					  daclinfo->defaclacl);
 
-	ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
-				 tag->data,
+	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
+					 tag->data,
 	   daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
-				 NULL,
-				 daclinfo->defaclrole,
-				 false, "DEFAULT ACL", SECTION_POST_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 NULL,
+					 daclinfo->defaclrole,
+					 false, "DEFAULT ACL", SECTION_POST_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(tag);
 	destroyPQExpBuffer(q);
@@ -14048,19 +14156,16 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
 static void
 dumpTable(Archive *fout, TableInfo *tbinfo)
 {
-	DumpOptions *dopt = fout->dopt;
-
-	if (tbinfo->dobj.dump && !dopt->dataOnly)
-	{
-		char	   *namecopy;
+	char		   *namecopy;
 
-		if (tbinfo->relkind == RELKIND_SEQUENCE)
-			dumpSequence(fout, tbinfo);
-		else
-			dumpTableSchema(fout, tbinfo);
+	if (tbinfo->relkind == RELKIND_SEQUENCE)
+		dumpSequence(fout, tbinfo);
+	else
+		dumpTableSchema(fout, tbinfo);
 
-		/* Handle the ACL here */
-		namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	/* Handle the ACL here */
+	namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 				(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
 				"TABLE",
@@ -14068,47 +14173,49 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 				tbinfo->relacl);
 
-		/*
-		 * Handle column ACLs, if any.  Note: we pull these with a separate
-		 * query rather than trying to fetch them during getTableAttrs, so
-		 * that we won't miss ACLs on system columns.
-		 */
-		if (fout->remoteVersion >= 80400)
-		{
-			PQExpBuffer query = createPQExpBuffer();
-			PGresult   *res;
-			int			i;
+	/*
+	 * Handle column ACLs, if any.  Note: we pull these with a separate
+	 * query rather than trying to fetch them during getTableAttrs, so
+	 * that we won't miss ACLs on system columns.
+	 */
+	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
+	{
+		PQExpBuffer query = createPQExpBuffer();
+		PGresult   *res;
+		int			i;
 
-			appendPQExpBuffer(query,
-					   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
-							  "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
-							  "ORDER BY attnum",
-							  tbinfo->dobj.catId.oid);
-			res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+		appendPQExpBuffer(query,
+				   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
+						  "WHERE attrelid = '%u' AND NOT attisdropped "
+						  "AND attacl IS NOT NULL "
+						  "ORDER BY attnum",
+						  tbinfo->dobj.catId.oid);
+		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
-			for (i = 0; i < PQntuples(res); i++)
-			{
-				char	   *attname = PQgetvalue(res, i, 0);
-				char	   *attacl = PQgetvalue(res, i, 1);
-				char	   *attnamecopy;
-				char	   *acltag;
-
-				attnamecopy = pg_strdup(fmtId(attname));
-				acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
-				/* Column's GRANT type is always TABLE */
-				dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
-						namecopy, attnamecopy, acltag,
-						tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-						attacl);
-				free(attnamecopy);
-				free(acltag);
-			}
-			PQclear(res);
-			destroyPQExpBuffer(query);
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			char	   *attname = PQgetvalue(res, i, 0);
+			char	   *attacl = PQgetvalue(res, i, 1);
+			char	   *attnamecopy;
+			char	   *acltag;
+
+			attnamecopy = pg_strdup(fmtId(attname));
+			acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
+			/* Column's GRANT type is always TABLE */
+			dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
+					namecopy, attnamecopy, acltag,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					attacl);
+			free(attnamecopy);
+			free(acltag);
 		}
-
-		free(namecopy);
+		PQclear(res);
+		destroyPQExpBuffer(query);
 	}
+
+	free(namecopy);
+
+	return;
 }
 
 /*
@@ -14786,24 +14893,28 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
 			(tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
-				 tbinfo->rolname,
+					 tbinfo->rolname,
 			   (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
-				 reltypename,
-				 tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 reltypename,
+					 tbinfo->postponed_def ?
+						SECTION_POST_DATA : SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Table Comments */
-	dumpTableComment(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpTableComment(fout, tbinfo, reltypename);
 
 	/* Dump Table Security Labels */
-	dumpTableSecLabel(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpTableSecLabel(fout, tbinfo, reltypename);
 
 	/* Dump comments on inlined table constraints */
 	for (j = 0; j < tbinfo->ncheck; j++)
@@ -14813,7 +14924,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		if (constr->separate || !constr->conislocal)
 			continue;
 
-		dumpTableConstraintComment(fout, constr);
+		if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpTableConstraintComment(fout, constr);
 	}
 
 	destroyPQExpBuffer(q);
@@ -14860,15 +14972,16 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 	appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
 					  fmtId(tbinfo->attnames[adnum - 1]));
 
-	ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
-				 tbinfo->attnames[adnum - 1],
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "DEFAULT", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
+					 tbinfo->attnames[adnum - 1],
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "DEFAULT", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -14975,24 +15088,26 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 		appendPQExpBuffer(delq, "%s;\n",
 						  fmtId(indxinfo->dobj.name));
 
-		ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
-					 indxinfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "INDEX", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
+						 indxinfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "INDEX", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 
 	/* Dump Index Comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				indxinfo->dobj.catId, 0,
-				is_constraint ? indxinfo->indexconstraint :
-				indxinfo->dobj.dumpId);
+	if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					indxinfo->dobj.catId, 0,
+					is_constraint ? indxinfo->indexconstraint :
+					indxinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -15103,15 +15218,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'f')
 	{
@@ -15136,15 +15252,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "FK CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "FK CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'c' && tbinfo)
 	{
@@ -15171,15 +15288,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else if (coninfo->contype == 'c' && tbinfo == NULL)
@@ -15207,15 +15325,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tyinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tyinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tyinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tyinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else
@@ -15225,7 +15344,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 	}
 
 	/* Dump Constraint Comments --- only works for table constraints */
-	if (tbinfo && coninfo->separate)
+	if (tbinfo && coninfo->separate &&
+		coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
 		dumpTableConstraintComment(fout, coninfo);
 
 	destroyPQExpBuffer(q);
@@ -15249,10 +15369,12 @@ dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
 					  fmtId(coninfo->dobj.name));
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				coninfo->dobj.catId, 0,
+
+	if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					coninfo->dobj.catId, 0,
 			 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(labelq);
@@ -15447,15 +15569,16 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 		binary_upgrade_extension_member(query, &tbinfo->dobj,
 										labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE", SECTION_PRE_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE", SECTION_PRE_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/*
 	 * If the sequence is owned by a table column, emit the ALTER for it as a
@@ -15483,25 +15606,29 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 			appendPQExpBuffer(query, ".%s;\n",
 						fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
 
-			ArchiveEntry(fout, nilCatalogId, createDumpId(),
-						 tbinfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname,
-						 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
-						 query->data, "", NULL,
-						 &(tbinfo->dobj.dumpId), 1,
-						 NULL, NULL);
+			if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, nilCatalogId, createDumpId(),
+							 tbinfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname,
+							 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
+							 query->data, "", NULL,
+							 &(tbinfo->dobj.dumpId), 1,
+							 NULL, NULL);
 		}
 	}
 
 	/* Dump Sequence Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -15550,15 +15677,16 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(query, ", %s, %s);\n",
 					  last, (called ? "true" : "false"));
 
-	ArchiveEntry(fout, nilCatalogId, createDumpId(),
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE SET", SECTION_DATA,
-				 query->data, "", NULL,
-				 &(tbinfo->dobj.dumpId), 1,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, nilCatalogId, createDumpId(),
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE SET", SECTION_DATA,
+					 query->data, "", NULL,
+					 &(tbinfo->dobj.dumpId), 1,
+					 NULL, NULL);
 
 	PQclear(res);
 
@@ -15757,19 +15885,21 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
-				 tginfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "TRIGGER", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
+						 tginfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "TRIGGER", SECTION_POST_DATA,
+						 query->data, delqry->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -15834,14 +15964,16 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
 	appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
 					  fmtId(evtinfo->dobj.name));
 
-	ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
-				 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
-				 "EVENT TRIGGER", SECTION_POST_DATA,
-				 query->data, "", NULL, NULL, 0, NULL, NULL);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
+					 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
+					 "EVENT TRIGGER", SECTION_POST_DATA,
+					 query->data, "", NULL, NULL, 0, NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				NULL, evtinfo->evtowner,
-				evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, evtinfo->evtowner,
+					evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(labelq);
@@ -15958,21 +16090,23 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 	appendPQExpBuffer(labelq, " ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
-				 rinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "RULE", SECTION_POST_DATA,
-				 cmd->data, delcmd->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
+					 rinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "RULE", SECTION_POST_DATA,
+					 cmd->data, delcmd->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump rule comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -16146,7 +16280,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 			{
 				TableInfo  *configtbl;
 				Oid			configtbloid = atooid(extconfigarray[j]);
-				bool		dumpobj = curext->dobj.dump;
+				bool		dumpobj =
+								curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
 
 				configtbl = findTableByOid(configtbloid);
 				if (configtbl == NULL)
@@ -16156,7 +16291,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 				 * Tables of not-to-be-dumped extensions shouldn't be dumped
 				 * unless the table or its schema is explicitly included
 				 */
-				if (!curext->dobj.dump)
+				if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
 				{
 					/* check table explicitly requested */
 					if (table_include_oids.head != NULL &&
@@ -16165,7 +16300,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 						dumpobj = true;
 
 					/* check table's schema explicitly requested */
-					if (configtbl->dobj.namespace->dobj.dump)
+					if (configtbl->dobj.namespace->dobj.dump &
+							DUMP_COMPONENT_DATA)
 						dumpobj = true;
 				}
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index c02c536..f479c06 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -81,6 +81,18 @@ typedef enum
 	DO_POLICY
 } DumpableObjectType;
 
+/* component types of an object which can be selected for dumping */
+typedef uint32 DumpComponents;	/* a bitmask of dump object components */
+#define DUMP_COMPONENT_NONE			(0)
+#define DUMP_COMPONENT_DEFINITION	(1 << 0)
+#define DUMP_COMPONENT_DATA			(1 << 1)
+#define DUMP_COMPONENT_COMMENT		(1 << 2)
+#define DUMP_COMPONENT_SECLABEL		(1 << 3)
+#define DUMP_COMPONENT_ACL			(1 << 4)
+#define DUMP_COMPONENT_POLICY		(1 << 5)
+#define DUMP_COMPONENT_USERMAP		(1 << 6)
+#define DUMP_COMPONENT_ALL			(0xFFFF)
+
 typedef struct _dumpableObject
 {
 	DumpableObjectType objType;
@@ -88,7 +100,7 @@ typedef struct _dumpableObject
 	DumpId		dumpId;			/* assigned by AssignDumpId() */
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
-	bool		dump;			/* true if we want to dump this object */
+	DumpComponents dump;	/* bitmask of components to dump */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From e764305e6d56a22e12e935a4eb8f346fb61f9553 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:44:21 -0400
Subject: [PATCH 3/5] In pg_dump, split "dump" into "dump" and "dump_contains"

Historically, the "dump" component of the namespace has been used
to decide if the objects inside of the namespace should be dumped
also.  Given that "dump" is now a bitmask and may be partial, and
we may want to dump out all components of the namespace object but
only some of the components of objects contained in the namespace,
create a "dump_contains" bitmask which will represent what components
of the objects inside of a namespace should be dumped out.

No behavior change here, but in preparation for a change where we
will dump out just the ACLs of objects in pg_catalog, but we might
not dump out the ACL of the pg_catalog namespace itself (for instance,
when it hasn't been changed from the value set at initdb time).
---
 src/bin/pg_dump/pg_dump.c | 21 ++++++++++++---------
 src/bin/pg_dump/pg_dump.h |  3 ++-
 2 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 5fa9992..650c17a 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1311,24 +1311,25 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 */
 
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
-		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
+			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
 							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
 	 */
-	if (nsinfo->dobj.dump &&
+	if (nsinfo->dobj.dump_contains &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1350,7 +1351,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 												   tbinfo->dobj.catId.oid) ?
 								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
-		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
+		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
 
 	/*
 	 * In any case, a table can be excluded by an exclusion switch
@@ -1407,7 +1408,8 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
+	/* Dump based on if the contents of the namespace are being dumped */
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
 }
 
 /*
@@ -1424,6 +1426,7 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	/* Default ACLs can't be extension members */
 
 	if (dinfo->dobj.namespace)
+		/* default ACLs are considered part of the namespace */
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
 		dinfo->dobj.dump = dopt->include_everything ?
@@ -1530,7 +1533,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	 * non-namespace-associated items, dump if we're dumping "everything".
 	 */
 	if (dobj->namespace)
-		dobj->dump = dobj->namespace->dobj.dump;
+		dobj->dump = dobj->namespace->dobj.dump_contains;
 	else
 		dobj->dump = dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index f479c06..85f9f48 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -100,7 +100,8 @@ typedef struct _dumpableObject
 	DumpId		dumpId;			/* assigned by AssignDumpId() */
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
-	DumpComponents dump;	/* bitmask of components to dump */
+	DumpComponents dump;		/* bitmask of components to dump */
+	DumpComponents dump_contains;		/* as above, but for contained objects */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From 89db2c63c6b36528f296e003e878d6eb802535e3 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 12:43:24 -0400
Subject: [PATCH 4/5] In pg_dump, include pg_catalog and extension ACLs, if
 changed

Now that all of the infrastructure exists, add in the ability to
dump out the ACLs of the objects inside of pg_catalog or the ACLs
for objects which are members of extensions, but only if they have
been changed from their original values.

The original values are tracked in pg_init_privs.  When pg_dump'ing
9.6-and-above databases, we will dump out the ACLs for all objects
in pg_catalog and the ACLs for all extension members, where the ACL
has been changed from the original value which was set during either
initdb or CREATE EXTENSION.

This should not change dumps against pre-9.6 databases.
---
 doc/src/sgml/extend.sgml     |   21 +
 src/bin/initdb/initdb.c      |    6 +-
 src/bin/pg_dump/dumputils.c  |  168 +++++-
 src/bin/pg_dump/dumputils.h  |    4 +-
 src/bin/pg_dump/pg_dump.c    | 1351 +++++++++++++++++++++++++++++++++++-------
 src/bin/pg_dump/pg_dump.h    |    8 +
 src/bin/pg_dump/pg_dumpall.c |    6 +-
 7 files changed, 1309 insertions(+), 255 deletions(-)

diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index 4a88381..df3b9d9 100644
--- a/doc/src/sgml/extend.sgml
+++ b/doc/src/sgml/extend.sgml
@@ -339,6 +339,27 @@
    </para>
 
    <para>
+    The extension script may set privileges on objects which are part of the
+    extension via <command>GRANT</command> and <command>REVOKE</command>
+    statements.  The final set of privileges for each object (if any are set)
+    will be stored in the
+    <link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link>
+    system catalog.  When <application>pg_dump</> is used, the
+    <command>CREATE EXTENSION</> command will be included in the dump, followed
+    by the set of <command>GRANT</command> and <command>REVOKE</command>
+    statements necessary to set the privileges on the objects to what they were
+    at the time the dump was taken.
+   </para>
+
+   <para>
+    <productname>PostgreSQL</> does not currently support extension scripts
+    issuing <command>CREATE POLICY</command> or <command>SECURITY LABEL</command>
+    statements.  These are expected to be set after the extension has been
+    created.  All RLS policies and security labels on extension objects will be
+    included in dumps created by <application>pg_dump</>.
+   </para>
+
+   <para>
     The extension mechanism also has provisions for packaging modification
     scripts that adjust the definitions of the SQL objects contained in an
     extension.  For example, if version 1.1 of an extension adds one function
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 858667b..18a3826 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -2002,7 +2002,11 @@ setup_privileges(FILE *cmdfd)
 	char	  **priv_lines;
 	static char *privileges_setup[] = {
 		"UPDATE pg_class "
-		"  SET relacl = E'{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
+		"  SET relacl = (SELECT array_agg(a.acl) FROM "
+		" (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
+		"  UNION SELECT unnest(pg_catalog.acldefault("
+		"    CASE WHEN relkind = 'S' THEN 's' ELSE 'r' END::\"char\",10::oid))"
+		" ) as a) "
 		"  WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n\n",
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 5301d3f..8dbc121 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -38,6 +38,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  *		TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
  *		FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
  *	acls: the ACL string fetched from the database
+ *	racls: the ACL string of any initial-but-now-revoked privileges
  *	owner: username of object owner (will be passed through fmtId); can be
  *		NULL or empty string to indicate "no owner known"
  *	prefix: string to prefix to each generated command; typically empty
@@ -54,13 +55,15 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  */
 bool
 buildACLCommands(const char *name, const char *subname,
-				 const char *type, const char *acls, const char *owner,
-				 const char *prefix, int remoteVersion,
+				 const char *type, const char *acls, const char *racls,
+				 const char *owner, const char *prefix, int remoteVersion,
 				 PQExpBuffer sql)
 {
 	bool		ok = true;
-	char	  **aclitems;
-	int			naclitems;
+	char	  **aclitems = NULL;
+	char	  **raclitems = NULL;
+	int			naclitems = 0;
+	int			nraclitems = 0;
 	int			i;
 	PQExpBuffer grantee,
 				grantor,
@@ -70,18 +73,31 @@ buildACLCommands(const char *name, const char *subname,
 				secondsql;
 	bool		found_owner_privs = false;
 
-	if (strlen(acls) == 0)
+	if (strlen(acls) == 0 && strlen(racls) == 0)
 		return true;			/* object has default permissions */
 
 	/* treat empty-string owner same as NULL */
 	if (owner && *owner == '\0')
 		owner = NULL;
 
-	if (!parsePGArray(acls, &aclitems, &naclitems))
+	if (strlen(acls) != 0)
 	{
-		if (aclitems)
-			free(aclitems);
-		return false;
+		if (!parsePGArray(acls, &aclitems, &naclitems))
+		{
+			if (aclitems)
+				free(aclitems);
+			return false;
+		}
+	}
+
+	if (strlen(racls) != 0)
+	{
+		if (!parsePGArray(racls, &raclitems, &nraclitems))
+		{
+			if (raclitems)
+				free(raclitems);
+			return false;
+		}
 	}
 
 	grantee = createPQExpBuffer();
@@ -90,24 +106,101 @@ buildACLCommands(const char *name, const char *subname,
 	privswgo = createPQExpBuffer();
 
 	/*
-	 * At the end, these two will be pasted together to form the result. But
-	 * the owner privileges need to go before the other ones to keep the
-	 * dependencies valid.  In recent versions this is normally the case, but
-	 * in old versions they come after the PUBLIC privileges and that results
-	 * in problems if we need to run REVOKE on the owner privileges.
+	 * At the end, these two will be pasted together to form the result.
+	 *
+	 * For older systems we use these to ensure that the owner privileges go
+	 * before the other ones, as a GRANT could create the default entry for
+	 * the object, which generally includes all rights for the owner. In more
+	 * recent versions we normally handle this because the owner rights come
+	 * first in the ACLs, but older versions might have them after the PUBLIC
+	 * privileges.
+	 *
+	 * For 9.6 and later systems, much of this changes.  With 9.6, we check
+	 * the default privileges for the objects at dump time and create two sets
+	 * of ACLs- "racls" which are the ACLs to REVOKE from the object (as the
+	 * object may have initial privileges on it, along with any default ACLs
+	 * which are not part of the current set of privileges), and regular
+	 * "acls", which are the ACLs to GRANT to the object.  We handle the
+	 * REVOKEs first, followed by the GRANTs.
 	 */
 	firstsql = createPQExpBuffer();
 	secondsql = createPQExpBuffer();
 
 	/*
-	 * Always start with REVOKE ALL FROM PUBLIC, so that we don't have to
-	 * wire-in knowledge about the default public privileges for different
-	 * kinds of objects.
+	 * For pre-9.6 systems, we always start with REVOKE ALL FROM PUBLIC, as we
+	 * don't wish to make any assumptions about what the default ACLs are, and
+	 * we do not collect them during the dump phase (and racls will always be
+	 * the empty set, see above).
+	 *
+	 * For 9.6 and later, if any revoke ACLs have been provided, then include
+	 * them in 'firstsql'.
+	 *
+	 * Revoke ACLs happen when an object starts out life with a set of
+	 * privileges (eg: GRANT SELECT ON pg_class TO PUBLIC;) and the user has
+	 * decided to revoke those rights.  Since those objects come into being
+	 * with those default privileges, we have to revoke them to match what the
+	 * current state of affairs is.  Note that we only started explicitly
+	 * tracking such initial rights in 9.6, and prior to that all initial
+	 * rights are actually handled by the simple 'REVOKE ALL .. FROM PUBLIC'
+	 * case, for initdb-created objects.  Prior to 9.6, we didn't handle
+	 * extensions correctly, but we do now by tracking their initial
+	 * privileges, in the same way we track initdb initial privileges, see
+	 * pg_init_privs.
 	 */
-	appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
-	if (subname)
-		appendPQExpBuffer(firstsql, "(%s)", subname);
-	appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+	if (remoteVersion < 90600)
+	{
+		Assert(nraclitems == 0);
+
+		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
+		if (subname)
+			appendPQExpBuffer(firstsql, "(%s)", subname);
+		appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+	}
+	else
+	{
+		/* Scan individual REVOKE ACL items */
+		for (i = 0; i < nraclitems; i++)
+		{
+			if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion,
+							  grantee, grantor, privs, privswgo))
+			{
+				ok = false;
+				break;
+			}
+
+			if (privs->len > 0 || privswgo->len > 0)
+			{
+				if (privs->len > 0)
+				{
+					appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s %s FROM ",
+									  prefix, privs->data, type, name);
+					if (grantee->len == 0)
+						appendPQExpBufferStr(firstsql, "PUBLIC;\n");
+					else if (strncmp(grantee->data, "group ",
+									 strlen("group ")) == 0)
+						appendPQExpBuffer(firstsql, "GROUP %s;\n",
+									fmtId(grantee->data + strlen("group ")));
+					else
+						appendPQExpBuffer(firstsql, "%s;\n",
+										  fmtId(grantee->data));
+				}
+				if (privswgo->len > 0)
+				{
+					appendPQExpBuffer(firstsql,
+							   "%sREVOKE GRANT OPTION FOR %s ON %s %s FROM ",
+									  prefix, privswgo->data, type, name);
+					if (grantee->len == 0)
+						appendPQExpBufferStr(firstsql, "PUBLIC");
+					else if (strncmp(grantee->data, "group ",
+									 strlen("group ")) == 0)
+						appendPQExpBuffer(firstsql, "GROUP %s",
+									fmtId(grantee->data + strlen("group ")));
+					else
+						appendPQExpBufferStr(firstsql, fmtId(grantee->data));
+				}
+			}
+		}
+	}
 
 	/*
 	 * We still need some hacking though to cover the case where new default
@@ -138,7 +231,14 @@ buildACLCommands(const char *name, const char *subname,
 
 		if (privs->len > 0 || privswgo->len > 0)
 		{
-			if (owner
+			/*
+			 * Prior to 9.6, we had to handle owner privileges in a special
+			 * manner by first REVOKE'ing the rights and then GRANT'ing them
+			 * after.  With 9.6 and above, what we need to REVOKE and what we
+			 * need to GRANT is figured out when we dump and stashed into
+			 * "racls" and "acls", respectivly.  See above.
+			 */
+			if (remoteVersion < 90600 && owner
 				&& strcmp(grantee->data, owner) == 0
 				&& strcmp(grantor->data, owner) == 0)
 			{
@@ -172,7 +272,14 @@ buildACLCommands(const char *name, const char *subname,
 			else
 			{
 				/*
-				 * Otherwise can assume we are starting from no privs.
+				 * For systems prior to 9.6, we can assume we are starting
+				 * from no privs at this point.
+				 *
+				 * For 9.6 and above, at this point we have issued REVOKE
+				 * statements for all initial and default privileges which are
+				 * no longer present on the object (as they were passed in as
+				 * 'racls') and we can simply GRANT the rights which are in
+				 * 'acls'.
 				 */
 				if (grantor->len > 0
 					&& (!owner || strcmp(owner, grantor->data) != 0))
@@ -215,9 +322,12 @@ buildACLCommands(const char *name, const char *subname,
 	}
 
 	/*
-	 * If we didn't find any owner privs, the owner must have revoked 'em all
+	 * For systems prior to 9.6, if we didn't find any owner privs, the owner
+	 * must have revoked 'em all.
+	 *
+	 * For 9.6 and above, we handle this through the 'racls'.  See above.
 	 */
-	if (!found_owner_privs && owner)
+	if (remoteVersion < 90600 && !found_owner_privs && owner)
 	{
 		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
 		if (subname)
@@ -235,7 +345,11 @@ buildACLCommands(const char *name, const char *subname,
 	destroyPQExpBuffer(firstsql);
 	destroyPQExpBuffer(secondsql);
 
-	free(aclitems);
+	if (aclitems)
+		free(aclitems);
+
+	if (raclitems)
+		free(raclitems);
 
 	return ok;
 }
@@ -275,7 +389,7 @@ buildDefaultACLCommands(const char *type, const char *nspname,
 		appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
 
 	result = buildACLCommands("", NULL,
-							  type, acls, owner,
+							  type, acls, "", owner,
 							  prefix->data, remoteVersion,
 							  sql);
 
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 4b404be..7637a46 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -37,8 +37,8 @@
 
 
 extern bool buildACLCommands(const char *name, const char *subname,
-				 const char *type, const char *acls, const char *owner,
-				 const char *prefix, int remoteVersion,
+				 const char *type, const char *acls, const char *racls,
+				 const char *owner, const char *prefix, int remoteVersion,
 				 PQExpBuffer sql);
 extern bool buildDefaultACLCommands(const char *type, const char *nspname,
 						const char *acls, const char *owner,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 650c17a..4c95504 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -206,7 +206,7 @@ static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 		const char *type, const char *name, const char *subname,
 		const char *tag, const char *nspname, const char *owner,
-		const char *acls);
+		const char *acls, const char *racls);
 
 static void getDependencies(Archive *fout);
 static void BuildArchiveDependencies(Archive *fout);
@@ -1268,7 +1268,7 @@ expand_table_name_patterns(Archive *fout,
  * Returns true if object is an extension member, else false.
  */
 static bool
-checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
+checkExtensionMembership(DumpableObject *dobj, Archive *fout)
 {
 	ExtensionInfo *ext = findOwningExtension(dobj->catId);
 
@@ -1281,12 +1281,26 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
 	addObjectDependency(dobj, ext->dobj.dumpId);
 
 	/*
-	 * Normally, mark the member object as not to be dumped.  But in binary
-	 * upgrades, we still dump the members individually, since the idea is to
-	 * exactly reproduce the database contents rather than replace the
-	 * extension contents with something different.
+	 * In 9.6 and above, mark the member object to have any non-initial ACL,
+	 * policies, and security lables dumped.
+	 *
+	 * Note that any initial ACLs (see pg_init_privs) will be removed when we
+	 * extract the information about the object.  We don't provide support for
+	 * initial policies and security labels and it seems unlikely for those to
+	 * ever exist, but we may have to revisit this later.
+	 *
+	 * Prior to 9.6, we do not include any extension member components.
+	 *
+	 * In binary upgrades, we still dump all components of the members
+	 * individually, since the idea is to exactly reproduce the database
+	 * contents rather than replace the extension contents with something
+	 * different.
 	 */
-	if (!dopt->binary_upgrade)
+	if (!fout->dopt->binary_upgrade && fout->remoteVersion >= 90600)
+		dobj->dump = DUMP_COMPONENT_ACL |
+			DUMP_COMPONENT_SECLABEL |
+			DUMP_COMPONENT_POLICY;
+	else if (!fout->dopt->binary_upgrade)
 		dobj->dump = DUMP_COMPONENT_NONE;
 	else
 		dobj->dump = ext->dobj.dump;
@@ -1299,9 +1313,9 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
  *		Mark a namespace as to be dumped or not
  */
 static void
-selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
+selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
 {
-	if (checkExtensionMembership(&nsinfo->dobj, dopt))
+	if (checkExtensionMembership(&nsinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1316,7 +1330,17 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
 			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
-							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+	else if (fout->remoteVersion >= 90600 &&
+			 strncmp(nsinfo->dobj.name, "pg_catalog",
+					 strlen("pg_catalog")) == 0)
+
+		/*
+		 * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
+		 * they are interesting (and not the original ACLs which were set at
+		 * initdb time, see pg_init_privs).
+		 */
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
@@ -1337,9 +1361,9 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
  *		Mark a table as to be dumped or not
  */
 static void
-selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
+selectDumpableTable(TableInfo *tbinfo, Archive *fout)
 {
-	if (checkExtensionMembership(&tbinfo->dobj, dopt))
+	if (checkExtensionMembership(&tbinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1349,7 +1373,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	if (table_include_oids.head != NULL)
 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
 												   tbinfo->dobj.catId.oid) ?
-								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
 
@@ -1376,7 +1400,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
  * object (the table or base type).
  */
 static void
-selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
+selectDumpableType(TypeInfo *tyinfo, Archive *fout)
 {
 	/* skip complex types, except for standalone composite types */
 	if (OidIsValid(tyinfo->typrelid) &&
@@ -1405,7 +1429,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 		 */
 	}
 
-	if (checkExtensionMembership(&tyinfo->dobj, dopt))
+	if (checkExtensionMembership(&tyinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/* Dump based on if the contents of the namespace are being dumped */
@@ -1443,15 +1467,15 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
  * OID is in the range reserved for initdb.
  */
 static void
-selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
+selectDumpableCast(CastInfo *cast, Archive *fout)
 {
-	if (checkExtensionMembership(&cast->dobj, dopt))
+	if (checkExtensionMembership(&cast->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		cast->dobj.dump = dopt->include_everything ?
+		cast->dobj.dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1464,15 +1488,15 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
  * language's OID is in the range reserved for initdb.
  */
 static void
-selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
+selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
 {
-	if (checkExtensionMembership(&plang->dobj, dopt))
+	if (checkExtensionMembership(&plang->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = dopt->include_everything ?
+		plang->dobj.dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1485,15 +1509,16 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
  * method's OID is in the range reserved for initdb.
  */
 static void
-selectDumpableAccessMethod(AccessMethodInfo *method, DumpOptions *dopt)
+selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 {
-	if (checkExtensionMembership(&method->dobj, dopt))
+	if (checkExtensionMembership(&method->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (method->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		method->dobj.dump = false;
+		method->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		method->dobj.dump = dopt->include_everything;
+		method->dobj.dump = fout->dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1523,9 +1548,9 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
  * Use this only for object types without a special-case routine above.
  */
 static void
-selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
+selectDumpableObject(DumpableObject *dobj, Archive *fout)
 {
-	if (checkExtensionMembership(dobj, dopt))
+	if (checkExtensionMembership(dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1535,7 +1560,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	if (dobj->namespace)
 		dobj->dump = dobj->namespace->dobj.dump_contains;
 	else
-		dobj->dump = dopt->include_everything ?
+		dobj->dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1978,22 +2003,22 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
 
 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
 		ArchiveEntry(fout,
-					 tdinfo->dobj.catId,	/* catalog ID */
-					 tdinfo->dobj.dumpId,	/* dump ID */
-					 tbinfo->dobj.name,		/* Name */
-					 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
-					 NULL,			/* Tablespace */
-					 tbinfo->rolname,		/* Owner */
-					 false,			/* with oids */
-					 "MATERIALIZED VIEW DATA",		/* Desc */
-					 SECTION_POST_DATA,		/* Section */
-					 q->data,		/* Create */
-					 "",			/* Del */
-					 NULL,			/* Copy */
-					 tdinfo->dobj.dependencies,		/* Deps */
-					 tdinfo->dobj.nDeps,	/* # Deps */
-					 NULL,			/* Dumper */
-					 NULL);			/* Dumper Arg */
+					 tdinfo->dobj.catId,		/* catalog ID */
+					 tdinfo->dobj.dumpId,		/* dump ID */
+					 tbinfo->dobj.name, /* Name */
+					 tbinfo->dobj.namespace->dobj.name, /* Namespace */
+					 NULL,		/* Tablespace */
+					 tbinfo->rolname,	/* Owner */
+					 false,		/* with oids */
+					 "MATERIALIZED VIEW DATA",	/* Desc */
+					 SECTION_POST_DATA, /* Section */
+					 q->data,	/* Create */
+					 "",		/* Del */
+					 NULL,		/* Copy */
+					 tdinfo->dobj.dependencies, /* Deps */
+					 tdinfo->dobj.nDeps,		/* # Deps */
+					 NULL,		/* Dumper */
+					 NULL);		/* Dumper Arg */
 
 	destroyPQExpBuffer(q);
 }
@@ -2729,12 +2754,19 @@ dumpStdStrings(Archive *AH)
 static void
 getBlobs(Archive *fout)
 {
+	DumpOptions *dopt = fout->dopt;
 	PQExpBuffer blobQry = createPQExpBuffer();
 	BlobInfo   *binfo;
 	DumpableObject *bdata;
 	PGresult   *res;
 	int			ntups;
 	int			i;
+	int			i_oid;
+	int			i_lomowner;
+	int			i_lomacl;
+	int			i_rlomacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Verbose message */
 	if (g_verbose)
@@ -2743,53 +2775,122 @@ getBlobs(Archive *fout)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(l.lomacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(l.lomacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('L',l.lomowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+			"EXCEPT "
+			" SELECT unnest(l.lomacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('L',l.lomowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(l.lomacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(l.lomacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN l.lomacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('L',l.lomowner))) "
+			"EXCEPT "
+			" SELECT unnest(l.lomacl)) as a)";
+	}
+
 	/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
-	if (fout->remoteVersion >= 90000)
+	if (fout->remoteVersion >= 90600)
 		appendPQExpBuffer(blobQry,
-						  "SELECT oid, (%s lomowner) AS rolname, lomacl"
+						  "SELECT l.oid, (%s l.lomowner) AS rolname, "
+						  "%s AS lomacl, "
+						  "%s AS rlomacl "
+						  "FROM pg_largeobject_metadata l "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(l.oid = pip.objoid AND pip.classoid = "
+				"(SELECT oid FROM pg_class WHERE relname = 'pg_largeobject')"
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	else if (fout->remoteVersion >= 90000)
+		appendPQExpBuffer(blobQry,
+						  "SELECT oid, (%s lomowner) AS rolname, lomacl, "
+						  "NULL AS rlomacl"
 						  " FROM pg_largeobject_metadata",
 						  username_subquery);
 	else if (fout->remoteVersion >= 70100)
 		appendPQExpBufferStr(blobQry,
-							 "SELECT DISTINCT loid, NULL::oid, NULL::oid"
+							 "SELECT DISTINCT loid, NULL::oid, NULL, "
+							 "NULL AS rlomacl "
 							 " FROM pg_largeobject");
 	else
 		appendPQExpBufferStr(blobQry,
-							 "SELECT oid, NULL::oid, NULL::oid"
+							 "SELECT oid, NULL::oid, NULL, "
+							 "NULL AS rlomacl "
 							 " FROM pg_class WHERE relkind = 'l'");
 
 	res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
 
+	i_oid = PQfnumber(res, "oid");
+	i_lomowner = PQfnumber(res, "rolname");
+	i_lomacl = PQfnumber(res, "lomacl");
+	i_rlomacl = PQfnumber(res, "rlomacl");
+
 	ntups = PQntuples(res);
-	if (ntups > 0)
+
+	/*
+	 * Each large object has its own BLOB archive entry.
+	 */
+	binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+
+	for (i = 0; i < ntups; i++)
 	{
-		/*
-		 * Each large object has its own BLOB archive entry.
-		 */
-		binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+		binfo[i].dobj.objType = DO_BLOB;
+		binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
+		binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+		AssignDumpId(&binfo[i].dobj);
 
-		for (i = 0; i < ntups; i++)
-		{
-			binfo[i].dobj.objType = DO_BLOB;
-			binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
-			binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
-			AssignDumpId(&binfo[i].dobj);
-
-			binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
-			if (!PQgetisnull(res, i, 1))
-				binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
-			else
-				binfo[i].rolname = "";
-			if (!PQgetisnull(res, i, 2))
-				binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
-			else
-				binfo[i].blobacl = NULL;
-		}
+		binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
+		binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
+		binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
+		binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
 
-		/*
-		 * If we have any large objects, a "BLOBS" archive entry is needed.
-		 * This is just a placeholder for sorting; it carries no data now.
-		 */
+		if (PQgetisnull(res, i, i_lomacl) && PQgetisnull(res, i, i_rlomacl))
+			binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
+	}
+
+	/*
+	 * If we have any large objects, a "BLOBS" archive entry is needed. This
+	 * is just a placeholder for sorting; it carries no data now.
+	 */
+	if (ntups > 0)
+	{
 		bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
 		bdata->objType = DO_BLOB_DATA;
 		bdata->catId = nilCatalogId;
@@ -2850,7 +2951,7 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
 		dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 				binfo->dobj.name, NULL, cquery->data,
-				NULL, binfo->rolname, binfo->blobacl);
+				NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl);
 
 	destroyPQExpBuffer(cquery);
 	destroyPQExpBuffer(dquery);
@@ -3381,6 +3482,9 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	int			i_nspname;
 	int			i_rolname;
 	int			i_nspacl;
+	int			i_rnspacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/*
 	 * Before 7.3, there are no real namespaces; create two dummy entries, one
@@ -3398,7 +3502,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[0].rolname = pg_strdup("");
 		nsinfo[0].nspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[0], dopt);
+		selectDumpableNamespace(&nsinfo[0], fout);
 
 		nsinfo[1].dobj.objType = DO_NAMESPACE;
 		nsinfo[1].dobj.catId.tableoid = 0;
@@ -3408,7 +3512,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[1].rolname = pg_strdup("");
 		nsinfo[1].nspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[1], dopt);
+		selectDumpableNamespace(&nsinfo[1], fout);
 
 		*numNamespaces = 2;
 
@@ -3421,13 +3525,103 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	selectSourceSchema(fout, "pg_catalog");
 
 	/*
+	 * To get the delta from what the permissions were at creation time
+	 * (either initdb or CREATE EXTENSION) vs. what they are now, we have to
+	 * look at two things:
+	 *
+	 * What privileges have been added, which we calculate by extracting all
+	 * the current privileges and then removing those which existed at
+	 * creation time, or which were there by default for the object.
+	 *
+	 * What privileges have been removed, which we calculate by extracting the
+	 * privileges as they were at creation time, and any privileges which were
+	 * there by default for the object, and then removing the current
+	 * privileges.
+	 *
+	 * If the ACL column is simply NULL then we just pass that through as a
+	 * NULL for both the 'privileges granted' and 'privileges revoked'.  No
+	 * ACL-related command will be included in such a case.
+	 *
+	 * We always perform this delta on ACLs which are created at initdb time,
+	 * since those will already be in place in any cluster we are restoring
+	 * into (binary upgrade or not).
+	 *
+	 * However, in binary upgrade mode, we perform the delta, in both
+	 * directions, without consideration for the initial privileges (those
+	 * tracked by pg_init_privs) on extension objects (but we must still
+	 * consider the default ACLs for the object), since we're dumping and
+	 * restoring those objects completely and the CREATE EXTENSION script
+	 * won't be re-run.
+	 */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(n.nspacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(n.nspacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('n',n.nspowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+			"EXCEPT "
+			" SELECT unnest(n.nspacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('n',n.nspowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(n.nspacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(n.nspacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN n.nspacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('n',n.nspowner))) "
+			"EXCEPT "
+			" SELECT unnest(n.nspacl)) as a)";
+	}
+
+	/*
 	 * we fetch all namespaces including system ones, so that every object we
 	 * read in can be linked to a containing namespace.
 	 */
-	appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
-					  "(%s nspowner) AS rolname, "
-					  "nspacl FROM pg_namespace",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+		appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "%s as nspacl, "
+						  "%s as rnspacl "
+						  "FROM pg_namespace n "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (n.oid = pip.objoid AND pip.classoid = "
+				 "(SELECT oid FROM pg_class WHERE relname = 'pg_namespace') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	else
+		appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "nspacl, NULL as rnspacl FROM pg_namespace",
+						  username_subquery);
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -3440,6 +3634,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	i_nspname = PQfnumber(res, "nspname");
 	i_rolname = PQfnumber(res, "rolname");
 	i_nspacl = PQfnumber(res, "nspacl");
+	i_rnspacl = PQfnumber(res, "rnspacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -3450,9 +3645,21 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
 		nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
+		nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
 
 		/* Decide whether to dump this namespace */
-		selectDumpableNamespace(&nsinfo[i], dopt);
+		selectDumpableNamespace(&nsinfo[i], fout);
+
+		/*
+		 * Do not try to dump ACL if the ACL is empty or the default.
+		 *
+		 * This is useful because, for some schemas/objects, the only
+		 * component we are going to try and dump is the ACL and if we can
+		 * remove that then 'dump' goes to zero/false and we don't consider
+		 * this object for dumping at all later on.
+		 */
+		if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl))
+			nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(nsinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
@@ -3612,6 +3819,7 @@ getTypes(Archive *fout, int *numTypes)
 	int			i_typname;
 	int			i_typnamespace;
 	int			i_typacl;
+	int			i_rtypacl;
 	int			i_rolname;
 	int			i_typinput;
 	int			i_typoutput;
@@ -3621,6 +3829,8 @@ getTypes(Archive *fout, int *numTypes)
 	int			i_typtype;
 	int			i_typisdefined;
 	int			i_isarray;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/*
 	 * we include even the built-in types because those may be used as array
@@ -3641,10 +3851,81 @@ getTypes(Archive *fout, int *numTypes)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90200)
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(t.typacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(t.typacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('T',t.typowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+			"EXCEPT "
+			" SELECT unnest(t.typacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('T',t.typowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(t.typacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(t.typacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN t.typacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('T',t.typowner))) "
+			"EXCEPT "
+			" SELECT unnest(t.typacl)) as a)";
+	}
+
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
+						  "t.typnamespace, "
+						  "%s AS typacl, "
+						  "%s AS rtypacl, "
+						  "(%s t.typowner) AS rolname, "
+						  "t.typinput::oid AS typinput, "
+					 "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, "
+						  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
+						  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
+						  "t.typtype, t.typisdefined, "
+						  "t.typname[0] = '_' AND t.typelem != 0 AND "
+						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
+						  "FROM pg_type t "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (t.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) ",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery);
+	}
+	else if (fout->remoteVersion >= 90200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, typacl, "
+						  "typnamespace, typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3659,7 +3940,7 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 80300)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, NULL AS typacl, "
+						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3674,7 +3955,7 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, NULL AS typacl, "
+						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3688,7 +3969,7 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 70100)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "0::oid AS typnamespace, NULL AS typacl, "
+				  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3704,7 +3985,7 @@ getTypes(Archive *fout, int *numTypes)
 		appendPQExpBuffer(query, "SELECT "
 		 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
 						  "oid, typname, "
-						  "0::oid AS typnamespace, NULL AS typacl, "
+				  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3727,6 +4008,7 @@ getTypes(Archive *fout, int *numTypes)
 	i_typname = PQfnumber(res, "typname");
 	i_typnamespace = PQfnumber(res, "typnamespace");
 	i_typacl = PQfnumber(res, "typacl");
+	i_rtypacl = PQfnumber(res, "rtypacl");
 	i_rolname = PQfnumber(res, "rolname");
 	i_typinput = PQfnumber(res, "typinput");
 	i_typoutput = PQfnumber(res, "typoutput");
@@ -3750,6 +4032,7 @@ getTypes(Archive *fout, int *numTypes)
 						  tyinfo[i].dobj.catId.oid);
 		tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
+		tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
 		tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
 		tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
 		tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
@@ -3767,7 +4050,11 @@ getTypes(Archive *fout, int *numTypes)
 			tyinfo[i].isArray = false;
 
 		/* Decide whether we want to dump it */
-		selectDumpableType(&tyinfo[i], dopt);
+		selectDumpableType(&tyinfo[i], fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl))
+			tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		/*
 		 * If it's a domain, fetch info about its constraints, if any
@@ -3875,7 +4162,6 @@ getTypes(Archive *fout, int *numTypes)
 OprInfo *
 getOperators(Archive *fout, int *numOprs)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -3961,7 +4247,7 @@ getOperators(Archive *fout, int *numOprs)
 		oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(oprinfo[i].dobj), dopt);
+		selectDumpableObject(&(oprinfo[i].dobj), fout);
 
 		if (strlen(oprinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
@@ -3985,7 +4271,6 @@ getOperators(Archive *fout, int *numOprs)
 CollInfo *
 getCollations(Archive *fout, int *numCollations)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4047,7 +4332,7 @@ getCollations(Archive *fout, int *numCollations)
 		collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(collinfo[i].dobj), dopt);
+		selectDumpableObject(&(collinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -4067,7 +4352,6 @@ getCollations(Archive *fout, int *numCollations)
 ConvInfo *
 getConversions(Archive *fout, int *numConversions)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4129,7 +4413,7 @@ getConversions(Archive *fout, int *numConversions)
 		convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(convinfo[i].dobj), dopt);
+		selectDumpableObject(&(convinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -4149,7 +4433,6 @@ getConversions(Archive *fout, int *numConversions)
 AccessMethodInfo *
 getAccessMethods(Archive *fout, int *numAccessMethods)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4203,7 +4486,7 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 		aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
 
 		/* Decide whether we want to dump it */
-		selectDumpableAccessMethod(&(aminfo[i]), dopt);
+		selectDumpableAccessMethod(&(aminfo[i]), fout);
 	}
 
 	PQclear(res);
@@ -4224,7 +4507,6 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 OpclassInfo *
 getOpclasses(Archive *fout, int *numOpclasses)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4296,7 +4578,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(opcinfo[i].dobj), dopt);
+		selectDumpableObject(&(opcinfo[i].dobj), fout);
 
 		if (fout->remoteVersion >= 70300)
 		{
@@ -4323,7 +4605,6 @@ getOpclasses(Archive *fout, int *numOpclasses)
 OpfamilyInfo *
 getOpfamilies(Archive *fout, int *numOpfamilies)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4385,7 +4666,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(opfinfo[i].dobj), dopt);
+		selectDumpableObject(&(opfinfo[i].dobj), fout);
 
 		if (fout->remoteVersion >= 70300)
 		{
@@ -4426,22 +4707,108 @@ getAggregates(Archive *fout, int *numAggs)
 	int			i_proargtypes;
 	int			i_rolname;
 	int			i_aggacl;
+	int			i_raggacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(p.proacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(p.proacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('f',p.proowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			"EXCEPT "
+			" SELECT unnest(p.proacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('f',p.proowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(p.proacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(p.proacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			"EXCEPT "
+			" SELECT unnest(p.proacl)) as a)";
+	}
+
 	/*
-	 * Find all user-defined aggregates.  See comment in getFuncs() for the
+	 * Find all interesting aggregates.  See comment in getFuncs() for the
 	 * rationale behind the filtering logic.
 	 */
-
-	if (fout->remoteVersion >= 80200)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
+						  "p.proname AS aggname, "
+						  "p.pronamespace AS aggnamespace, "
+						  "p.pronargs, p.proargtypes, "
+						  "(%s p.proowner) AS rolname, "
+						  "%s AS aggacl, "
+						  "%s AS raggacl "
+						  "FROM pg_proc p "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(p.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE p.proisagg AND ("
+						  "p.pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
+	}
+	else if (fout->remoteVersion >= 80200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
 						  "pronamespace AS aggnamespace, "
 						  "pronargs, proargtypes, "
 						  "(%s proowner) AS rolname, "
-						  "proacl AS aggacl "
+						  "proacl AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_proc p "
 						  "WHERE proisagg AND ("
 						  "pronamespace != "
@@ -4464,7 +4831,8 @@ getAggregates(Archive *fout, int *numAggs)
 						  "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
 						  "proargtypes, "
 						  "(%s proowner) AS rolname, "
-						  "proacl AS aggacl "
+						  "proacl AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_proc "
 						  "WHERE proisagg "
 						  "AND pronamespace != "
@@ -4478,7 +4846,8 @@ getAggregates(Archive *fout, int *numAggs)
 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 						  "aggbasetype AS proargtypes, "
 						  "(%s aggowner) AS rolname, "
-						  "NULL AS aggacl "
+						  "NULL AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_aggregate "
 						  "where oid > '%u'::oid",
 						  username_subquery,
@@ -4493,7 +4862,8 @@ getAggregates(Archive *fout, int *numAggs)
 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 						  "aggbasetype AS proargtypes, "
 						  "(%s aggowner) AS rolname, "
-						  "NULL AS aggacl "
+						  "NULL AS aggacl, "
+						  "NULL AS raggacl "
 						  "FROM pg_aggregate "
 						  "where oid > '%u'::oid",
 						  username_subquery,
@@ -4515,6 +4885,7 @@ getAggregates(Archive *fout, int *numAggs)
 	i_proargtypes = PQfnumber(res, "proargtypes");
 	i_rolname = PQfnumber(res, "rolname");
 	i_aggacl = PQfnumber(res, "aggacl");
+	i_raggacl = PQfnumber(res, "raggacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -4534,6 +4905,7 @@ getAggregates(Archive *fout, int *numAggs)
 		agginfo[i].aggfn.lang = InvalidOid;		/* not currently interesting */
 		agginfo[i].aggfn.prorettype = InvalidOid;		/* not saved */
 		agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
+		agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
 		agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
 		if (agginfo[i].aggfn.nargs == 0)
 			agginfo[i].aggfn.argtypes = NULL;
@@ -4550,7 +4922,11 @@ getAggregates(Archive *fout, int *numAggs)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(agginfo[i].aggfn.dobj), dopt);
+		selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl))
+			agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4586,17 +4962,69 @@ getFuncs(Archive *fout, int *numFuncs)
 	int			i_proargtypes;
 	int			i_prorettype;
 	int			i_proacl;
+	int			i_rproacl;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(p.proacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(p.proacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('f',p.proowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			"EXCEPT "
+			" SELECT unnest(p.proacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('f',p.proowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(p.proacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(p.proacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN p.proacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('f',p.proowner))) "
+			"EXCEPT "
+			" SELECT unnest(p.proacl)) as a)";
+	}
+
 	/*
-	 * Find all user-defined functions.  Normally we can exclude functions in
-	 * pg_catalog, which is worth doing since there are several thousand of
-	 * 'em.  However, there are some extensions that create functions in
-	 * pg_catalog.  In normal dumps we can still ignore those --- but in
-	 * binary-upgrade mode, we must dump the member objects of the extension,
-	 * so be sure to fetch any such functions.
+	 * Find all interesting functions.  We include functions in pg_catalog, if
+	 * they have an ACL different from what we set at initdb time (which is
+	 * saved in pg_init_privs for us to perform this check).  There may also
+	 * be functions which are members of extensions which we must dump if we
+	 * are in binary upgrade mode (we'll mark those functions as to-be-dumped
+	 * when we check if the extension is to-be-dumped and we're in binary
+	 * upgrade mode).
 	 *
 	 * Also, in 9.2 and up, exclude functions that are internally dependent on
 	 * something else, since presumably those will be created as a result of
@@ -4605,13 +5033,50 @@ getFuncs(Archive *fout, int *numFuncs)
 	 * because the constructors don't have any dependencies the range type
 	 * doesn't have; otherwise we might not get creation ordering correct.
 	 */
-
-	if (fout->remoteVersion >= 70300)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query,
+						  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
+						  "p.pronargs, p.proargtypes, p.prorettype, "
+						  "%s AS proacl, "
+						  "%s AS rproacl, "
+						  "p.pronamespace, "
+						  "(%s p.proowner) AS rolname "
+						  "FROM pg_proc p "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(p.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE NOT proisagg "
+						  "AND NOT EXISTS (SELECT 1 FROM pg_depend "
+						  "WHERE classid = 'pg_proc'::regclass AND "
+						  "objid = p.oid AND deptype = 'i') AND ("
+						  "pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+							   "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
+	}
+	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query,
 						  "SELECT tableoid, oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, proacl, "
-						  "pronamespace, "
+						  "NULL as rproacl, pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc p "
 						  "WHERE NOT proisagg AND ("
@@ -4639,6 +5104,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "SELECT tableoid, oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, "
 						  "NULL AS proacl, "
+						  "NULL AS rproacl, "
 						  "0::oid AS pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc "
@@ -4655,6 +5121,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, "
 						  "NULL AS proacl, "
+						  "NULL AS rproacl, "
 						  "0::oid AS pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc "
@@ -4681,6 +5148,7 @@ getFuncs(Archive *fout, int *numFuncs)
 	i_proargtypes = PQfnumber(res, "proargtypes");
 	i_prorettype = PQfnumber(res, "prorettype");
 	i_proacl = PQfnumber(res, "proacl");
+	i_rproacl = PQfnumber(res, "rproacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -4697,6 +5165,7 @@ getFuncs(Archive *fout, int *numFuncs)
 		finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
 		finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
 		finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
+		finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
 		finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
 		if (finfo[i].nargs == 0)
 			finfo[i].argtypes = NULL;
@@ -4708,7 +5177,11 @@ getFuncs(Archive *fout, int *numFuncs)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(finfo[i].dobj), dopt);
+		selectDumpableObject(&(finfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl))
+			finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(finfo[i].rolname) == 0)
 			write_msg(NULL,
@@ -4725,7 +5198,7 @@ getFuncs(Archive *fout, int *numFuncs)
 
 /*
  * getTables
- *	  read all the user-defined tables (no indexes, no catalogs)
+ *	  read all the tables (no indexes)
  * in the system catalogs return them in the TableInfo* structure
  *
  * numTables is set to the number of tables read in
@@ -4745,6 +5218,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_relnamespace;
 	int			i_relkind;
 	int			i_relacl;
+	int			i_rrelacl;
 	int			i_rolname;
 	int			i_relchecks;
 	int			i_relhastriggers;
@@ -4769,6 +5243,8 @@ getTables(Archive *fout, int *numTables)
 	int			i_toastreloptions;
 	int			i_reloftype;
 	int			i_relpages;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
@@ -4793,7 +5269,106 @@ getTables(Archive *fout, int *numTables)
 	 * we cannot correctly identify inherited columns, owned sequences, etc.
 	 */
 
-	if (fout->remoteVersion >= 90500)
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(c.relacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(c.relacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('r',c.relowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+			"EXCEPT "
+			" SELECT unnest(c.relacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('r',c.relowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(c.relacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(c.relacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN c.relacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('r',c.relowner))) "
+			"EXCEPT "
+			" SELECT unnest(c.relacl)) as a)";
+	}
+
+	if (fout->remoteVersion >= 90600)
+	{
+		/*
+		 * Left join to pick up dependency info linking sequences to their
+		 * owning column, if any (note this dependency is AUTO as of 8.2)
+		 *
+		 * Left join to detect if any privileges are still as-set-at-init, in
+		 * which case we won't dump out ACL commands for those.
+		 */
+		appendPQExpBuffer(query,
+						  "SELECT c.tableoid, c.oid, c.relname, "
+						  "%s AS relacl, %s as rrelacl, "
+						  "c.relkind, c.relnamespace, "
+						  "(%s c.relowner) AS rolname, "
+						  "c.relchecks, c.relhastriggers, "
+						  "c.relhasindex, c.relhasrules, c.relhasoids, "
+						  "c.relrowsecurity, c.relforcerowsecurity, "
+						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
+						  "tc.relfrozenxid AS tfrozenxid, "
+						  "tc.relminmxid AS tminmxid, "
+						  "c.relpersistence, c.relispopulated, "
+						  "c.relreplident, c.relpages, "
+						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+						  "d.refobjid AS owning_tab, "
+						  "d.refobjsubid AS owning_col, "
+						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
+						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
+						  "tc.reloptions AS toast_reloptions "
+						  "FROM pg_class c "
+						  "LEFT JOIN pg_depend d ON "
+						  "(c.relkind = '%c' AND "
+						  "d.classid = c.tableoid AND d.objid = c.oid AND "
+						  "d.objsubid = 0 AND "
+						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
+					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(c.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_class') AND pip.objsubid = 0) "
+				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
+						  "ORDER BY c.oid",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery,
+						  RELKIND_SEQUENCE,
+						  RELKIND_RELATION, RELKIND_SEQUENCE,
+						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
+	}
+	else if (fout->remoteVersion >= 90500)
 	{
 		/*
 		 * Left join to pick up dependency info linking sequences to their
@@ -4801,7 +5376,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4842,7 +5418,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4884,7 +5461,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4926,7 +5504,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4966,7 +5545,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5005,7 +5585,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5044,7 +5625,8 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 					  "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5083,7 +5665,7 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, relname, "
-						  "relacl, relkind, relnamespace, "
+						  "relacl, NULL as rrelacl, relkind, relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 						  "relhasindex, relhasrules, relhasoids, "
@@ -5121,7 +5703,7 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, relname, "
-						  "relacl, relkind, relnamespace, "
+						  "relacl, NULL as rrelacl, relkind, relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 						  "relhasindex, relhasrules, relhasoids, "
@@ -5154,7 +5736,8 @@ getTables(Archive *fout, int *numTables)
 	else if (fout->remoteVersion >= 70200)
 	{
 		appendPQExpBuffer(query,
-						  "SELECT tableoid, oid, relname, relacl, relkind, "
+						  "SELECT tableoid, oid, relname, relacl, "
+						  "NULL as rrelacl, relkind, "
 						  "0::oid AS relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5182,7 +5765,8 @@ getTables(Archive *fout, int *numTables)
 	{
 		/* all tables have oids in 7.1 */
 		appendPQExpBuffer(query,
-						  "SELECT tableoid, oid, relname, relacl, relkind, "
+						  "SELECT tableoid, oid, relname, relacl, "
+						  "NULL as rrelacl, relkind, "
 						  "0::oid AS relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5216,7 +5800,7 @@ getTables(Archive *fout, int *numTables)
 		appendPQExpBuffer(query,
 						  "SELECT "
 		"(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
-						  "oid, relname, relacl, "
+						  "oid, relname, relacl, NULL as rrelacl, "
 						  "CASE WHEN relhasrules and relkind = 'r' "
 					  "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
 					  "             r.ev_class = c.oid AND r.ev_type = '1') "
@@ -5270,6 +5854,7 @@ getTables(Archive *fout, int *numTables)
 	i_relname = PQfnumber(res, "relname");
 	i_relnamespace = PQfnumber(res, "relnamespace");
 	i_relacl = PQfnumber(res, "relacl");
+	i_rrelacl = PQfnumber(res, "rrelacl");
 	i_relkind = PQfnumber(res, "relkind");
 	i_rolname = PQfnumber(res, "rolname");
 	i_relchecks = PQfnumber(res, "relchecks");
@@ -5324,6 +5909,7 @@ getTables(Archive *fout, int *numTables)
 						  tblinfo[i].dobj.catId.oid);
 		tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
+		tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
 		tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
 		tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
 		tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
@@ -5371,7 +5957,7 @@ getTables(Archive *fout, int *numTables)
 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
 			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
 		else
-			selectDumpableTable(&tblinfo[i], dopt);
+			selectDumpableTable(&tblinfo[i], fout);
 
 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
@@ -6457,7 +7043,6 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 EventTriggerInfo *
 getEventTriggers(Archive *fout, int *numEventTriggers)
 {
-	DumpOptions *dopt = fout->dopt;
 	int			i;
 	PQExpBuffer query;
 	PGresult   *res;
@@ -6527,7 +7112,7 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 		evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(evtinfo[i].dobj), dopt);
+		selectDumpableObject(&(evtinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -6563,17 +7148,88 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	int			i_laninline;
 	int			i_lanvalidator;
 	int			i_lanacl;
+	int			i_rlanacl;
 	int			i_lanowner;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90000)
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(l.lanacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(l.lanacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('l',l.lanowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+			"EXCEPT "
+			" SELECT unnest(l.lanacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('l',l.lanowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(l.lanacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(l.lanacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN l.lanacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('l',l.lanowner))) "
+			"EXCEPT "
+			" SELECT unnest(l.lanacl)) as a)";
+	}
+
+	if (fout->remoteVersion >= 90600)
+	{
+		/* pg_language has a laninline column */
+		appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
+						  "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
+						  "l.laninline, l.lanvalidator, "
+						  "%s AS lanacl, "
+						  "%s AS rlanacl, "
+						  "(%s l.lanowner) AS lanowner "
+						  "FROM pg_language l "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (l.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE l.lanispl "
+						  "ORDER BY l.oid",
+						  acl_subquery,
+						  racl_subquery,
+						  username_subquery);
+	}
+	else if (fout->remoteVersion >= 90000)
 	{
 		/* pg_language has a laninline column */
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
-						  "laninline, lanvalidator, lanacl, "
+						  "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
 						  "(%s lanowner) AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6586,6 +7242,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "(%s lanowner) AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6598,6 +7255,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "(%s '10') AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6610,6 +7268,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "(%s '1') AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6622,6 +7281,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6632,6 +7292,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+						  "NULL AS rlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6644,6 +7305,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 						  "oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+						  "NULL AS rlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6666,6 +7328,7 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	i_laninline = PQfnumber(res, "laninline");
 	i_lanvalidator = PQfnumber(res, "lanvalidator");
 	i_lanacl = PQfnumber(res, "lanacl");
+	i_rlanacl = PQfnumber(res, "rlanacl");
 	i_lanowner = PQfnumber(res, "lanowner");
 
 	for (i = 0; i < ntups; i++)
@@ -6681,10 +7344,15 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
 		planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
 		planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
+		planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
 		planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
 
 		/* Decide whether we want to dump it */
-		selectDumpableProcLang(&(planginfo[i]), dopt);
+		selectDumpableProcLang(&(planginfo[i]), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl))
+			planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (fout->remoteVersion < 70300)
 		{
@@ -6717,7 +7385,6 @@ getProcLangs(Archive *fout, int *numProcLangs)
 CastInfo *
 getCasts(Archive *fout, int *numCasts)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -6823,7 +7490,7 @@ getCasts(Archive *fout, int *numCasts)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableCast(&(castinfo[i]), dopt);
+		selectDumpableCast(&(castinfo[i]), fout);
 	}
 
 	PQclear(res);
@@ -6859,7 +7526,6 @@ get_language_name(Archive *fout, Oid langid)
 TransformInfo *
 getTransforms(Archive *fout, int *numTransforms)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -6934,7 +7600,7 @@ getTransforms(Archive *fout, int *numTransforms)
 		free(lanname);
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(transforminfo[i].dobj), dopt);
+		selectDumpableObject(&(transforminfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7545,7 +8211,6 @@ shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
 TSParserInfo *
 getTSParsers(Archive *fout, int *numTSParsers)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7618,7 +8283,7 @@ getTSParsers(Archive *fout, int *numTSParsers)
 		prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(prsinfo[i].dobj), dopt);
+		selectDumpableObject(&(prsinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7638,7 +8303,6 @@ getTSParsers(Archive *fout, int *numTSParsers)
 TSDictInfo *
 getTSDictionaries(Archive *fout, int *numTSDicts)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7704,7 +8368,7 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 			dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(dictinfo[i].dobj), dopt);
+		selectDumpableObject(&(dictinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7724,7 +8388,6 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 TSTemplateInfo *
 getTSTemplates(Archive *fout, int *numTSTemplates)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7782,7 +8445,7 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 		tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(tmplinfo[i].dobj), dopt);
+		selectDumpableObject(&(tmplinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7802,7 +8465,6 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 TSConfigInfo *
 getTSConfigurations(Archive *fout, int *numTSConfigs)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7861,7 +8523,7 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 		cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(cfginfo[i].dobj), dopt);
+		selectDumpableObject(&(cfginfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7894,7 +8556,10 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	int			i_fdwhandler;
 	int			i_fdwvalidator;
 	int			i_fdwacl;
+	int			i_rfdwacl;
 	int			i_fdwoptions;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Before 8.4, there are no foreign-data wrappers */
 	if (fout->remoteVersion < 80400)
@@ -7903,17 +8568,89 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 		return NULL;
 	}
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(f.fdwacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(f.fdwacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('F',f.fdwowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+			"EXCEPT "
+			" SELECT unnest(f.fdwacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('F',f.fdwowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(f.fdwacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(f.fdwacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN f.fdwacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('F',f.fdwowner))) "
+			"EXCEPT "
+			" SELECT unnest(f.fdwacl)) as a)";
+	}
+
 	query = createPQExpBuffer();
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90100)
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
+						  "(%s f.fdwowner) AS rolname, "
+						  "f.fdwhandler::pg_catalog.regproc, "
+						  "f.fdwvalidator::pg_catalog.regproc, "
+						  "%s AS fdwacl, "
+						  "%s AS rfdwacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.fdwoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS fdwoptions "
+						  "FROM pg_foreign_data_wrapper f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_data_wrapper') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	}
+	else if (fout->remoteVersion >= 90100)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
 						  "(%s fdwowner) AS rolname, "
 						  "fdwhandler::pg_catalog.regproc, "
 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
+						  "NULL as rfdwacl, "
 						  "array_to_string(ARRAY("
 						  "SELECT quote_ident(option_name) || ' ' || "
 						  "quote_literal(option_value) "
@@ -7929,6 +8666,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 						  "(%s fdwowner) AS rolname, "
 						  "'-' AS fdwhandler, "
 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
+						  "NULL as rfdwacl, "
 						  "array_to_string(ARRAY("
 						  "SELECT quote_ident(option_name) || ' ' || "
 						  "quote_literal(option_value) "
@@ -7953,6 +8691,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	i_fdwhandler = PQfnumber(res, "fdwhandler");
 	i_fdwvalidator = PQfnumber(res, "fdwvalidator");
 	i_fdwacl = PQfnumber(res, "fdwacl");
+	i_rfdwacl = PQfnumber(res, "rfdwacl");
 	i_fdwoptions = PQfnumber(res, "fdwoptions");
 
 	for (i = 0; i < ntups; i++)
@@ -7968,9 +8707,14 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 		fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
 		fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
 		fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
+		fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(fdwinfo[i].dobj), dopt);
+		selectDumpableObject(&(fdwinfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl))
+			fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8004,7 +8748,10 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	int			i_srvtype;
 	int			i_srvversion;
 	int			i_srvacl;
+	int			i_rsrvacl;
 	int			i_srvoptions;
+	char	   *acl_subquery;
+	char	   *racl_subquery;
 
 	/* Before 8.4, there are no foreign servers */
 	if (fout->remoteVersion < 80400)
@@ -8013,22 +8760,96 @@ getForeignServers(Archive *fout, int *numForeignServers)
 		return NULL;
 	}
 
+	/* see comments in getNamespaces */
+	if (dopt->binary_upgrade)
+	{
+		acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(f.srvacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+			") as a) "
+			"ELSE "
+			"(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			" (SELECT unnest(f.srvacl) as acl EXCEPT "
+			"  SELECT unnest(acldefault('S',f.srvowner)) "
+			") as a) "
+			"END";
+		racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+			"(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+			"EXCEPT "
+			" SELECT unnest(f.srvacl)) as a) "
+			"ELSE "
+			" (SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(acldefault('S',f.srvowner)) as acl "
+			"EXCEPT "
+			"SELECT unnest(f.srvacl)) as a) "
+			"END";
+	}
+	else
+	{
+		acl_subquery = "(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"(SELECT unnest(f.srvacl) as acl EXCEPT "
+			" (SELECT unnest(pip.initprivs) "
+			"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+			") as a)";
+		racl_subquery = "(SELECT CASE WHEN f.srvacl IS NOT NULL THEN "
+			"array_agg(acl) END FROM "
+			"((SELECT unnest(pip.initprivs) as acl "
+			"  UNION SELECT unnest(acldefault('S',f.srvowner))) "
+			"EXCEPT "
+			" SELECT unnest(f.srvacl)) as a)";
+	}
+
 	query = createPQExpBuffer();
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
-					  "(%s srvowner) AS rolname, "
-					  "srvfdw, srvtype, srvversion, srvacl,"
-					  "array_to_string(ARRAY("
-					  "SELECT quote_ident(option_name) || ' ' || "
-					  "quote_literal(option_value) "
-					  "FROM pg_options_to_table(srvoptions) "
-					  "ORDER BY option_name"
-					  "), E',\n    ') AS srvoptions "
-					  "FROM pg_foreign_server",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
+						  "(%s f.srvowner) AS rolname, "
+						  "f.srvfdw, f.srvtype, f.srvversion, "
+						  "%s AS srvacl, "
+						  "%s AS rsrvacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions "
+						  "FROM pg_foreign_server f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+			"(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_server') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery,
+						  racl_subquery);
+	}
+	else
+	{
+		appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
+						  "(%s srvowner) AS rolname, "
+						  "srvfdw, srvtype, srvversion, srvacl, "
+						  "NULL AS rsrvacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions "
+						  "FROM pg_foreign_server",
+						  username_subquery);
+	}
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -8045,6 +8866,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	i_srvtype = PQfnumber(res, "srvtype");
 	i_srvversion = PQfnumber(res, "srvversion");
 	i_srvacl = PQfnumber(res, "srvacl");
+	i_rsrvacl = PQfnumber(res, "rsrvacl");
 	i_srvoptions = PQfnumber(res, "srvoptions");
 
 	for (i = 0; i < ntups; i++)
@@ -8061,9 +8883,14 @@ getForeignServers(Archive *fout, int *numForeignServers)
 		srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
 		srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
 		srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
+		srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(srvinfo[i].dobj), dopt);
+		selectDumpableObject(&(srvinfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl))
+			srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8688,7 +9515,7 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
 				qnspname, NULL, nspinfo->dobj.name, NULL,
-				nspinfo->rolname, nspinfo->nspacl);
+				nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl);
 
 	free(qnspname);
 
@@ -8983,7 +9810,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9121,7 +9948,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9196,7 +10023,7 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -9590,7 +10417,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9758,7 +10585,7 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	/* Dump any per-constraint comments */
 	for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9993,7 +10820,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -10311,7 +11138,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 				qlanname, NULL, plang->dobj.name,
 				lanschema,
-				plang->lanowner, plang->lanacl);
+				plang->lanowner, plang->lanacl, plang->rlanacl);
 
 	free(qlanname);
 
@@ -10982,7 +11809,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
 				funcsig, NULL, funcsig_tag,
 				finfo->dobj.namespace->dobj.name,
-				finfo->rolname, finfo->proacl);
+				finfo->rolname, finfo->proacl, finfo->rproacl);
 
 	PQclear(res);
 
@@ -12700,29 +13527,29 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	if (fout->remoteVersion >= 90600)
 	{
 		appendPQExpBuffer(query, "SELECT aggtransfn, "
-			"aggfinalfn, aggtranstype::pg_catalog.regtype, "
-			"aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
-			"aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
-			"aggfinalextra, aggmfinalextra, "
-			"aggsortop::pg_catalog.regoperator, "
-			"aggserialtype::pg_catalog.regtype, "
-			"(aggkind = 'h') AS hypothetical, "
-			"aggtransspace, agginitval, "
-			"aggmtransspace, aggminitval, "
-			"true AS convertok, "
-			"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
-			"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
-			"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
-			"WHERE a.aggfnoid = p.oid "
-			"AND p.oid = '%u'::pg_catalog.oid",
-			agginfo->aggfn.dobj.catId.oid);
+						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+					"aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
+		   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
+						  "aggfinalextra, aggmfinalextra, "
+						  "aggsortop::pg_catalog.regoperator, "
+						  "aggserialtype::pg_catalog.regtype, "
+						  "(aggkind = 'h') AS hypothetical, "
+						  "aggtransspace, agginitval, "
+						  "aggmtransspace, aggminitval, "
+						  "true AS convertok, "
+				  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
+		 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
+					  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
+						  "WHERE a.aggfnoid = p.oid "
+						  "AND p.oid = '%u'::pg_catalog.oid",
+						  agginfo->aggfn.dobj.catId.oid);
 	}
 	else if (fout->remoteVersion >= 90400)
 	{
 		appendPQExpBuffer(query, "SELECT aggtransfn, "
 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
-						  "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
+						"'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
 						  "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
 						  "aggfinalextra, aggmfinalextra, "
 						  "aggsortop::pg_catalog.regoperator, "
@@ -13047,7 +13874,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 		dumpSecLabel(fout, labelq->data,
 					 agginfo->aggfn.dobj.namespace->dobj.name,
 					 agginfo->aggfn.rolname,
-					 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+				   agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
 	/*
 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
@@ -13065,7 +13892,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 				"FUNCTION",
 				aggsig, NULL, aggsig_tag,
 				agginfo->aggfn.dobj.namespace->dobj.name,
-				agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+				agginfo->aggfn.rolname, agginfo->aggfn.proacl,
+				agginfo->aggfn.rproacl);
 
 	free(aggsig);
 	if (aggfullsig)
@@ -13509,7 +14337,7 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 				"FOREIGN DATA WRAPPER",
 				qfdwname, NULL, fdwinfo->dobj.name,
 				NULL, fdwinfo->rolname,
-				fdwinfo->fdwacl);
+				fdwinfo->fdwacl, fdwinfo->rfdwacl);
 
 	/* Dump Foreign Data Wrapper Comments */
 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13605,7 +14433,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 				"FOREIGN SERVER",
 				qsrvname, NULL, srvinfo->dobj.name,
 				NULL, srvinfo->rolname,
-				srvinfo->srvacl);
+				srvinfo->srvacl, srvinfo->rsrvacl);
 
 	/* Dump user mappings */
 	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
@@ -13784,7 +14612,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
 					 tag->data,
-	   daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
+		daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
 					 NULL,
 					 daclinfo->defaclrole,
 					 false, "DEFAULT ACL", SECTION_POST_DATA,
@@ -13811,13 +14639,15 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
  * 'owner' is the owner, NULL if there is no owner (for languages).
  * 'acls' is the string read out of the fooacl system catalog field;
  *		it will be parsed here.
+ * 'racls' contains any initial ACLs that the object had which have now been
+ *		revoked by the user, it will also be parsed here.
  *----------
  */
 static void
 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 		const char *type, const char *name, const char *subname,
 		const char *tag, const char *nspname, const char *owner,
-		const char *acls)
+		const char *acls, const char *racls)
 {
 	DumpOptions *dopt = fout->dopt;
 	PQExpBuffer sql;
@@ -13832,7 +14662,7 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 
 	sql = createPQExpBuffer();
 
-	if (!buildACLCommands(name, subname, type, acls, owner,
+	if (!buildACLCommands(name, subname, type, acls, racls, owner,
 						  "", fout->remoteVersion, sql))
 		exit_horribly(NULL,
 					"could not parse ACL list (%s) for object \"%s\" (%s)\n",
@@ -14159,7 +14989,8 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
 static void
 dumpTable(Archive *fout, TableInfo *tbinfo)
 {
-	char		   *namecopy;
+	DumpOptions *dopt = fout->dopt;
+	char	   *namecopy;
 
 	if (tbinfo->relkind == RELKIND_SEQUENCE)
 		dumpSequence(fout, tbinfo);
@@ -14174,31 +15005,107 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 				"TABLE",
 				namecopy, NULL, tbinfo->dobj.name,
 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tbinfo->relacl);
+				tbinfo->relacl, tbinfo->rrelacl);
 
 	/*
-	 * Handle column ACLs, if any.  Note: we pull these with a separate
-	 * query rather than trying to fetch them during getTableAttrs, so
-	 * that we won't miss ACLs on system columns.
+	 * Handle column ACLs, if any.  Note: we pull these with a separate query
+	 * rather than trying to fetch them during getTableAttrs, so that we won't
+	 * miss ACLs on system columns.
 	 */
 	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
 	{
 		PQExpBuffer query = createPQExpBuffer();
 		PGresult   *res;
 		int			i;
+		char	   *acl_subquery;
+		char	   *racl_subquery;
+
+		/* see comments in getNamespaces */
+		if (dopt->binary_upgrade)
+		{
+			acl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+				"(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+				"array_agg(acl) END FROM "
+				"(SELECT unnest(at.attacl) as acl EXCEPT "
+				" (SELECT unnest(pip.initprivs) "
+				"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+				") as a) "
+				"ELSE "
+				"(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+				"array_agg(acl) END FROM "
+				" (SELECT unnest(at.attacl) as acl EXCEPT "
+				"  SELECT unnest(acldefault('c',c.relowner)) "
+				") as a) "
+				"END";
+			racl_subquery = "CASE WHEN pip.privtype = 'i' THEN "
+				"(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+				"array_agg(acl) END FROM "
+				"((SELECT unnest(pip.initprivs) as acl "
+				"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+				"EXCEPT "
+				" SELECT unnest(at.attacl)) as a) "
+				"ELSE "
+				" (SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+				"array_agg(acl) END FROM "
+				"(SELECT unnest(acldefault('c',c.relowner)) as acl "
+				"EXCEPT "
+				"SELECT unnest(at.attacl)) as a) "
+				"END";
+		}
+		else
+		{
+			acl_subquery = "(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+				"array_agg(acl) END FROM "
+				"(SELECT unnest(at.attacl) as acl EXCEPT "
+				" (SELECT unnest(pip.initprivs) "
+				"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+				") as a)";
+			racl_subquery = "(SELECT CASE WHEN at.attacl IS NOT NULL THEN "
+				"array_agg(acl) END FROM "
+				"((SELECT unnest(pip.initprivs) as acl "
+				"  UNION SELECT unnest(acldefault('c',c.relowner))) "
+				"EXCEPT "
+				" SELECT unnest(at.attacl)) as a)";
+		}
+
+		if (fout->remoteVersion >= 90600)
+		{
+			appendPQExpBuffer(query,
+							  "SELECT at.attname, "
+							  "%s AS attacl, "
+							  "%s AS rattacl "
+							  "FROM pg_catalog.pg_attribute at "
+					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+							  "LEFT JOIN pg_init_privs pip ON "
+							  "(pip.classoid = "
+				 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
+				   " at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
+							  "WHERE at.attrelid = '%u' AND "
+							  "NOT at.attisdropped "
+							  "AND at.attacl IS NOT NULL "
+							  "ORDER BY at.attnum",
+							  acl_subquery,
+							  racl_subquery,
+							  tbinfo->dobj.catId.oid);
+		}
+		else
+		{
+			appendPQExpBuffer(query,
+							  "SELECT attname, attacl, NULL as rattacl "
+							  "FROM pg_catalog.pg_attribute "
+							  "WHERE attrelid = '%u' AND NOT attisdropped "
+							  "AND attacl IS NOT NULL "
+							  "ORDER BY attnum",
+							  tbinfo->dobj.catId.oid);
+		}
 
-		appendPQExpBuffer(query,
-				   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
-						  "WHERE attrelid = '%u' AND NOT attisdropped "
-						  "AND attacl IS NOT NULL "
-						  "ORDER BY attnum",
-						  tbinfo->dobj.catId.oid);
 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
 		for (i = 0; i < PQntuples(res); i++)
 		{
 			char	   *attname = PQgetvalue(res, i, 0);
 			char	   *attacl = PQgetvalue(res, i, 1);
+			char	   *rattacl = PQgetvalue(res, i, 2);
 			char	   *attnamecopy;
 			char	   *acltag;
 
@@ -14208,7 +15115,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 			dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
 					namecopy, attnamecopy, acltag,
 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-					attacl);
+					attacl, rattacl);
 			free(attnamecopy);
 			free(acltag);
 		}
@@ -14905,7 +15812,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			   (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
 					 reltypename,
 					 tbinfo->postponed_def ?
-						SECTION_POST_DATA : SECTION_PRE_DATA,
+					 SECTION_POST_DATA : SECTION_PRE_DATA,
 					 q->data, delq->data, NULL,
 					 NULL, 0,
 					 NULL, NULL);
@@ -15889,15 +16796,15 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 					  fmtId(tbinfo->dobj.name));
 
 	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
-			ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
-						 tginfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname, false,
-						 "TRIGGER", SECTION_POST_DATA,
-						 query->data, delqry->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+		ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
+					 tginfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "TRIGGER", SECTION_POST_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
 		dumpComment(fout, labelq->data,
@@ -16284,7 +17191,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 				TableInfo  *configtbl;
 				Oid			configtbloid = atooid(extconfigarray[j]);
 				bool		dumpobj =
-								curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
+				curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
 
 				configtbl = findTableByOid(configtbloid);
 				if (configtbl == NULL)
@@ -16304,7 +17211,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 
 					/* check table's schema explicitly requested */
 					if (configtbl->dobj.namespace->dobj.dump &
-							DUMP_COMPONENT_DATA)
+						DUMP_COMPONENT_DATA)
 						dumpobj = true;
 				}
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 85f9f48..4c4ad89 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -113,6 +113,7 @@ typedef struct _namespaceInfo
 	DumpableObject dobj;
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *nspacl;
+	char	   *rnspacl;
 } NamespaceInfo;
 
 typedef struct _extensionInfo
@@ -135,6 +136,7 @@ typedef struct _typeInfo
 	 */
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *typacl;
+	char	   *rtypacl;
 	Oid			typelem;
 	Oid			typrelid;
 	char		typrelkind;		/* 'r', 'v', 'c', etc */
@@ -164,6 +166,7 @@ typedef struct _funcInfo
 	Oid		   *argtypes;
 	Oid			prorettype;
 	char	   *proacl;
+	char	   *rproacl;
 } FuncInfo;
 
 /* AggInfo is a superset of FuncInfo */
@@ -220,6 +223,7 @@ typedef struct _tableInfo
 	DumpableObject dobj;
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *relacl;
+	char	   *rrelacl;
 	char		relkind;
 	char		relpersistence; /* relation persistence */
 	bool		relispopulated; /* relation is populated */
@@ -388,6 +392,7 @@ typedef struct _procLangInfo
 	Oid			laninline;
 	Oid			lanvalidator;
 	char	   *lanacl;
+	char	   *rlanacl;
 	char	   *lanowner;		/* name of owner, or empty string */
 } ProcLangInfo;
 
@@ -457,6 +462,7 @@ typedef struct _fdwInfo
 	char	   *fdwvalidator;
 	char	   *fdwoptions;
 	char	   *fdwacl;
+	char	   *rfdwacl;
 } FdwInfo;
 
 typedef struct _foreignServerInfo
@@ -467,6 +473,7 @@ typedef struct _foreignServerInfo
 	char	   *srvtype;
 	char	   *srvversion;
 	char	   *srvacl;
+	char	   *rsrvacl;
 	char	   *srvoptions;
 } ForeignServerInfo;
 
@@ -483,6 +490,7 @@ typedef struct _blobInfo
 	DumpableObject dobj;
 	char	   *rolname;
 	char	   *blobacl;
+	char	   *rblobacl;
 } BlobInfo;
 
 /*
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 530d3f4..a594937 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1113,8 +1113,8 @@ dumpTablespaces(PGconn *conn)
 							  fspcname, spcoptions);
 
 		if (!skip_acls &&
-			!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner,
-							  "", server_version, buf))
+			!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, "",
+							  spcowner, "", server_version, buf))
 		{
 			fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
 					progname, spcacl, fspcname);
@@ -1444,7 +1444,7 @@ dumpCreateDB(PGconn *conn)
 		}
 
 		if (!skip_acls &&
-			!buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner,
+			!buildACLCommands(fdbname, NULL, "DATABASE", dbacl, "", dbowner,
 							  "", server_version, buf))
 		{
 			fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
-- 
2.5.0


From 03bddf4ea3c68cdb75169401146733e8afdf4a87 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 14 Mar 2016 11:05:25 -0400
Subject: [PATCH 5/5] Use GRANT system to manage access to sensitive functions

Now that pg_dump will properly dump out any ACL changes made to
functions which exist in pg_catalog, switch to using the GRANT system
to manage access to those functions.

This means removing 'if (!superuser()) ereport()' checks from the
functions themselves and then REVOKEing EXECUTE right from 'public' for
these functions in system_views.sql.
---
 doc/src/sgml/backup.sgml               |  8 ++++--
 doc/src/sgml/func.sgml                 | 17 ++++++------
 doc/src/sgml/monitoring.sgml           | 12 ++++++---
 src/backend/access/transam/xlogfuncs.c | 48 +++++++++++++---------------------
 src/backend/catalog/system_views.sql   | 20 ++++++++++++++
 src/backend/postmaster/pgstat.c        | 24 +++++++----------
 src/backend/utils/adt/misc.c           | 16 +++++-------
 7 files changed, 76 insertions(+), 69 deletions(-)

diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 9092cf8..8c65df2 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -826,7 +826,9 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 &amp;&amp; cp pg_xlog/
    </listitem>
    <listitem>
     <para>
-     Connect to the database as a superuser and issue the command:
+     Connect to the database as a user with rights to run pg_start_backup
+     (superuser, or a user who has been granted EXECUTE on the function)
+     and issue the command:
 <programlisting>
 SELECT pg_start_backup('label');
 </programlisting>
@@ -877,7 +879,9 @@ SELECT pg_start_backup('label', true);
    </listitem>
    <listitem>
     <para>
-     Again connect to the database as a superuser, and issue the command:
+     Again connect to the database as a user with rights to run
+     pg_stop_backup (superuser, or a user who has been granted EXECUTE on
+     the function), and issue the command:
 <programlisting>
 SELECT pg_stop_backup();
 </programlisting>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 1bc9fbc..283769d 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17302,8 +17302,9 @@ SELECT set_config('log_statement_stats', 'off', false);
    <para>
     The functions shown in <xref
     linkend="functions-admin-signal-table"> send control signals to
-    other server processes.  Use of these functions is usually restricted
-    to superusers, with noted exceptions.
+    other server processes.  Use of these functions is restricted to
+    superusers by default but access may be granted to others with the
+    <command>GRANT</command>, with noted exceptions.
    </para>
 
    <table id="functions-admin-signal-table">
@@ -17453,7 +17454,7 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_create_restore_point(<parameter>name</> <type>text</>)</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Create a named point for performing restore (restricted to superusers)</entry>
+       <entry>Create a named point for performing restore (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
@@ -17481,14 +17482,14 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> </optional>)</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Prepare for performing on-line backup (restricted to superusers or replication roles)</entry>
+       <entry>Prepare for performing on-line backup (restricted to superusers or replication roles by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_stop_backup()</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Finish performing on-line backup (restricted to superusers or replication roles)</entry>
+       <entry>Finish performing on-line backup (restricted to superusers or replication roles by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
@@ -17509,7 +17510,7 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_switch_xlog()</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Force switch to a new transaction log file (restricted to superusers)</entry>
+       <entry>Force switch to a new transaction log file (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
@@ -17766,7 +17767,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
         <literal><function>pg_xlog_replay_pause()</function></literal>
         </entry>
        <entry><type>void</type></entry>
-       <entry>Pauses recovery immediately (restricted to superusers).
+       <entry>Pauses recovery immediately (restricted to superusers by default, but other users can be granted EXECUTE to run the function).
        </entry>
       </row>
       <row>
@@ -17774,7 +17775,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
         <literal><function>pg_xlog_replay_resume()</function></literal>
         </entry>
        <entry><type>void</type></entry>
-       <entry>Restarts recovery if it was paused (restricted to superusers).
+       <entry>Restarts recovery if it was paused (restricted to superusers by default, but other users can be granted EXECUTE to run the function).
        </entry>
       </row>
      </tbody>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 105d541..5ab3acc 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2289,7 +2289,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset all statistics counters for the current database to zero
-       (requires superuser privileges)
+       (requires superuser privileges by default, but EXECUTE for this
+       function can be granted to others.)
       </entry>
      </row>
 
@@ -2298,7 +2299,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset some cluster-wide statistics counters to zero, depending on the
-       argument (requires superuser privileges).
+       argument (requires superuser privileges by default, but EXECUTE for
+       this functiion can be granted to others).
        Calling <literal>pg_stat_reset_shared('bgwriter')</> will zero all the
        counters shown in the <structname>pg_stat_bgwriter</> view.
        Calling <literal>pg_stat_reset_shared('archiver')</> will zero all the
@@ -2311,7 +2313,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset statistics for a single table or index in the current database to
-       zero (requires superuser privileges)
+       zero (requires superuser privileges by default, but EXECUTE for this
+       function can be granted to others)
       </entry>
      </row>
 
@@ -2320,7 +2323,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset statistics for a single function in the current database to
-       zero (requires superuser privileges)
+       zero (requires superuser privileges by default, but EXECUTE for this
+       function can be granted to others)
       </entry>
      </row>
     </tbody>
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 9ec6b2a..f7daa8e 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -43,6 +43,9 @@
  * contains the user-supplied label string (typically this would be used
  * to tell where the backup dump will be stored) and the starting time and
  * starting WAL location for the dump.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_start_backup(PG_FUNCTION_ARGS)
@@ -55,11 +58,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
 
 	backupidstr = text_to_cstring(backupid);
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		   errmsg("must be superuser or replication role to run a backup")));
-
 	/* Make sure we can open the directory with tablespaces in it */
 	dir = AllocateDir("pg_tblspc");
 	if (!dir)
@@ -86,17 +84,15 @@ pg_start_backup(PG_FUNCTION_ARGS)
  * record for that and the file is for informational and debug purposes only.
  *
  * Note: different from CancelBackup which just cancels online backup mode.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_stop_backup(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	stoppoint;
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		 (errmsg("must be superuser or replication role to run a backup"))));
-
 	stoppoint = do_pg_stop_backup(NULL, true, NULL);
 
 	PG_RETURN_LSN(stoppoint);
@@ -104,17 +100,15 @@ pg_stop_backup(PG_FUNCTION_ARGS)
 
 /*
  * pg_switch_xlog: switch to next xlog file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_switch_xlog(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	switchpoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-			 (errmsg("must be superuser to switch transaction log files"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -131,6 +125,9 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
 
 /*
  * pg_create_restore_point: a named point for restore
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_create_restore_point(PG_FUNCTION_ARGS)
@@ -139,11 +136,6 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
 	char	   *restore_name_str;
 	XLogRecPtr	restorepoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to create a restore point"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -365,15 +357,13 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_pause - pause recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -387,15 +377,13 @@ pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_resume - resume recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_resume(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 9ae1ef4..c867451 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -997,3 +997,23 @@ RETURNS text[]
 LANGUAGE INTERNAL
 STRICT IMMUTABLE
 AS 'parse_ident';
+
+-- The default permissions for functions mean that anyone can execute them.
+-- A number of functions shouldn't be executable by just anyone, but rather
+-- than use explicit 'superuser()' checks in those functions, we use the GRANT
+-- system to REVOKE access to those functions at initdb time.  Administrators
+-- can later change who can access these functions, or leave them as only
+-- available to superuser / cluster owner, if they choose.
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_switch_xlog() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_pause() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_resume() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_rotate_logfile() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public;
+
+REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_table_counters(oid) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM public;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 1467355..41f4374 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -1217,6 +1217,9 @@ pgstat_drop_relation(Oid relid)
  * pgstat_reset_counters() -
  *
  *	Tell the statistics collector to reset counters for our database.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1227,11 +1230,6 @@ pgstat_reset_counters(void)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETCOUNTER);
 	msg.m_databaseid = MyDatabaseId;
 	pgstat_send(&msg, sizeof(msg));
@@ -1241,6 +1239,9 @@ pgstat_reset_counters(void)
  * pgstat_reset_shared_counters() -
  *
  *	Tell the statistics collector to reset cluster-wide shared counters.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1251,11 +1252,6 @@ pgstat_reset_shared_counters(const char *target)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	if (strcmp(target, "archiver") == 0)
 		msg.m_resettarget = RESET_ARCHIVER;
 	else if (strcmp(target, "bgwriter") == 0)
@@ -1274,6 +1270,9 @@ pgstat_reset_shared_counters(const char *target)
  * pgstat_reset_single_counter() -
  *
  *	Tell the statistics collector to reset a single counter.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1284,11 +1283,6 @@ pgstat_reset_single_counter(Oid objoid, PgStat_Single_Reset_Type type)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSINGLECOUNTER);
 	msg.m_databaseid = MyDatabaseId;
 	msg.m_resettype = type;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 6f7c407..ebc7bb3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -321,15 +321,13 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
 
 /*
  * Signal to reload the database configuration
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_reload_conf(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to signal the postmaster"))));
-
 	if (kill(PostmasterPid, SIGHUP))
 	{
 		ereport(WARNING,
@@ -343,15 +341,13 @@ pg_reload_conf(PG_FUNCTION_ARGS)
 
 /*
  * Rotate log file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_rotate_logfile(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to rotate log files"))));
-
 	if (!Logging_collector)
 	{
 		ereport(WARNING,
-- 
2.5.0

#7José Luis Tallón
jltallon@adv-solutions.net
In reply to: Stephen Frost (#6)

On 04/02/2016 03:23 AM, Stephen Frost wrote: [snip]

Patch does not apply cleanly (via "git am") as of today's master; but does apply with "patch"; minor fuzzes apart, so tested with that.

Just needed to be rebased and then updated to reflect the additions of
dumping the access methods to pg_dump. Updated patch series attached.

Confirmed clean, thanks! :)

* Initial ACL preservation:
" * Note that any initial ACLs (see pg_init_privs) will be removed when we
* extract the information about the object. We don't provide support for
* initial policies and security labels and it seems unlikely for those
* to ever exist, but we may have to revisit this later.
" ... fair enough, but it ought to be documented in the manual, too. IMO.
Fixed.

Check.

DOCUMENTATION
- Under "privtype" it says: "A code defining the type of initial privilege of this object; see text" ... but the patch doesn't seem to contain the referenced text�?
A minor omission, definitively --- it is indeed easily derived from enum InitPrivsType's definition at include/catalog/pg_init_privs.h
Fixed.

Check

[snip]

Within buildACLCommands(), multiple ocurrences of strncmp( ... ,"group ", strlen("group ") could have been avoided, but code simplicity/readability could be affected
... whereas in other places one reads "if( strncmp(nsinfo->dobj.name, "pg_catalog", 10) == 0) "

Fixed by doing 'strlen("pg_catalog")' in the one spot which had been
using a hard-coded value of '10'.

Ok. I tend to do ".... ,10 /*strlen("pg_catalog")*/ , ... " instead,
but this is definitively good.

[snip]
The new status of this patch is: Ready for Committer
Very cool.

Thanks again for the review!

Thank you, Stephen

/ J.L.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Stephen Frost
sfrost@snowman.net
In reply to: Stephen Frost (#6)
1 attachment(s)

Jose, all,

While reviewing and considering this patch further, I realized that
a pg_upgrade correctly restored the privileges of extension objects, but
it didn't copy through the pg_init_privs catalog entries for those
extension objects, meaning that a further pg_dump wouldn't realize that
the extension objects had any initial privileges.

After looking at a few options, I settled on taking an approach similar
to how extension dependencies are handled and created a backend function
to help out with that issue. The backend function, only callable during
binary upgrade, sets a flag to let the system know that the GRANTs and
REVOKEs about to be executed need to be recorded into pg_init_privs,
just like they are done during a CREATE EXTENSION script. pg_dump now
pulls out, during a binary upgrade for extension objects, what the delta
is between the object's default privileges and what is recorded in
pg_init_privs and issues the necessary GRANT and REVOKE statements in a
block surrounded by setting/unsetting of the flag.

That turned out to simplify the regular pg_dump extraction process for
ACLs as that part could then simply always assume that the objects in
the system start life with the privileges recorded in pg_init_privs (as
they always were for initdb'd objects but now, by the time we reach the
point where we are issuing the GRANTs and REVOKEs for the extension
objects, those are as well).

With all of these changes to the ACL extension bits of the queries, I
pulled those out into a single buildACLQueries() function instead of
repeating the more-or-less-the-same query fragments inside of every
get*() routine in pg_dump. That refactoring really cleaned up the
pg_dump changes from that patch, in my view.

I also rebased the patch and dealt with the fallout from other recent
changes which have gone into the tree.

I'll be doing more testing, review and clean-up (there are some
whitespace only changes in the later patches that really should be
included in the earlier patches where the code was actually changed)
tonight with plans to push this tomorrow night.

Thanks!

Stephen

Attachments:

catalog_acls_v7.patchtext/x-diff; charset=us-asciiDownload
From 57bb8a2fd83e23aab2bc9b08c55c8a3b462e50d6 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Thu, 10 Mar 2016 20:56:09 -0500
Subject: [PATCH 1/5] Add new catalog called pg_init_privs

This new catalog holds the privileges which the system was
initialized with at initdb time, along with any permissions set
by extensions at CREATE EXTENSION time.  This allows pg_dump
(and any other similar use-cases) to detect when the privileges
set on initdb-created or extension-created objects have been
changed from what they were set to at initdb/extension-creation
time and handle those changes appropriately.
---
 doc/src/sgml/catalogs.sgml                 | 108 +++++++++++++++++++++
 src/backend/catalog/Makefile               |   2 +-
 src/backend/catalog/aclchk.c               | 149 +++++++++++++++++++++++++++++
 src/backend/catalog/dependency.c           |  46 ++++++++-
 src/bin/initdb/initdb.c                    | 143 +++++++++++++++++++++++++++
 src/include/catalog/indexing.h             |   3 +
 src/include/catalog/pg_init_privs.h        | 101 +++++++++++++++++++
 src/test/regress/expected/sanity_check.out |   1 +
 8 files changed, 549 insertions(+), 4 deletions(-)
 create mode 100644 src/include/catalog/pg_init_privs.h

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index bb75229..c8897f4 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -179,6 +179,11 @@
      </row>
 
      <row>
+      <entry><link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link></entry>
+      <entry>object initial privileges</entry>
+     </row>
+
+     <row>
       <entry><link linkend="catalog-pg-language"><structname>pg_language</structname></link></entry>
       <entry>languages for writing functions</entry>
      </row>
@@ -3772,6 +3777,109 @@
 
  </sect1>
 
+ <sect1 id="catalog-pg-init-privs">
+  <title><structname>pg_init_privs</structname></title>
+
+  <indexterm zone="catalog-pg-init-privs">
+   <primary>pg_init_privs</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_init_privs</> records information about
+   the initial privileges of objects in the system.  There is one entry
+   for each object in the database which has a non-default (non-NULL)
+   initial set of privileges.
+  </para>
+
+  <para>
+   Objects can have initial privileges either by having those privileges set
+   when the system is initialized (by <application>initdb</>) or when the
+   object is created during a <command>CREATE EXTENSION</command> and the
+   extension script sets initial privileges using the <command>GRANT</command>
+   system.  Note that the system will automatically handle recording of the
+   privileges during the extension script and that extension authors need
+   only use the <command>GRANT</command> and <command>REVOKE</command>
+   statements in their script to have the privileges recorded.  The
+   <literal>privtype</literal> column indicates if the initial privilege was
+   set by <application>initdb</> or during a
+   <command>CREATE EXTENSION</command> command.
+  </para>
+
+  <para>
+   Objects which have initial privileges set by <application>initdb</> will
+   have entries where <literal>privtype</literal> is
+   <literal>'i'</literal>, while objects which have initial privileges set
+   by <command>CREATE EXTENSION</command> will have entries where
+   <literal>privtype</literal> is <literal>'e'</literal>.
+  </para>
+
+  <table>
+   <title><structname>pg_inherits</> Columns</title>
+
+   <tgroup cols="4">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>objoid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry>any OID column</entry>
+      <entry>The OID of the specific object</entry>
+     </row>
+
+     <row>
+      <entry><structfield>classoid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
+      <entry>The OID of the system catalog the object is in</entry>
+     </row>
+
+     <row>
+      <entry><structfield>objsubid</structfield></entry>
+      <entry><type>int4</type></entry>
+      <entry></entry>
+      <entry>
+       For a table column, this is the column number (the
+       <structfield>objoid</> and <structfield>classoid</> refer to the
+       table itself).  For all other object types, this column is
+       zero.
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>privtype</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>
+       A code defining the type of initial privilege of this object; see text
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>initprivs</structfield></entry>
+      <entry><type>aclitem[]</type></entry>
+      <entry></entry>
+      <entry>
+       The initial access privileges; see
+       <xref linkend="sql-grant"> and
+       <xref linkend="sql-revoke">
+       for details
+      </entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
 
  <sect1 id="catalog-pg-language">
   <title><structname>pg_language</structname></title>
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 25130ec..1ce7610 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -40,7 +40,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_ts_parser.h pg_ts_template.h pg_extension.h \
 	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
 	pg_foreign_table.h pg_policy.h pg_replication_origin.h \
-	pg_default_acl.h pg_seclabel.h pg_shseclabel.h \
+	pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
 	pg_collation.h pg_range.h pg_transform.h \
 	toasting.h indexing.h \
     )
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 0f3bc07..ffb6678 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -35,6 +35,7 @@
 #include "catalog/pg_extension.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
+#include "catalog/pg_init_privs.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_largeobject_metadata.h"
@@ -49,6 +50,7 @@
 #include "catalog/pg_ts_dict.h"
 #include "commands/dbcommands.h"
 #include "commands/event_trigger.h"
+#include "commands/extension.h"
 #include "commands/proclang.h"
 #include "commands/tablespace.h"
 #include "foreign/foreign.h"
@@ -119,6 +121,8 @@ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
 						 AttrNumber att_number, const char *colname);
 static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
 		   Oid roleid, AclMode mask, AclMaskHow how);
+static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
+						Acl *new_acl);
 
 
 #ifdef ACLDEBUG
@@ -1678,6 +1682,10 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(attRelation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(relOid, RelationRelationId, attnum,
+								ACL_NUM(new_acl) > 0 ? new_acl : NULL);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(RelationRelationId, relOid, attnum,
 							  ownerId,
@@ -1939,6 +1947,9 @@ ExecGrant_Relation(InternalGrant *istmt)
 			/* keep the catalog indexes up to date */
 			CatalogUpdateIndexes(relation, newtuple);
 
+			/* Update initial privileges for extensions */
+			recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
+
 			/* Update the shared dependency ACL info */
 			updateAclDependencies(RelationRelationId, relOid, 0,
 								  ownerId,
@@ -2254,6 +2265,10 @@ ExecGrant_Fdw(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
+								new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ForeignDataWrapperRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2379,6 +2394,9 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ForeignServerRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2503,6 +2521,9 @@ ExecGrant_Function(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(ProcedureRelationId, funcId, 0,
 							  ownerId,
@@ -2633,6 +2654,9 @@ ExecGrant_Language(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
 							  ownerId,
@@ -2772,6 +2796,9 @@ ExecGrant_Largeobject(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(LargeObjectRelationId,
 							  HeapTupleGetOid(tuple), 0,
@@ -2897,6 +2924,9 @@ ExecGrant_Namespace(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
 							  ownerId,
@@ -3158,6 +3188,9 @@ ExecGrant_Type(InternalGrant *istmt)
 		/* keep the catalog indexes up to date */
 		CatalogUpdateIndexes(relation, newtuple);
 
+		/* Update initial privileges for extensions */
+		recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
+
 		/* Update the shared dependency ACL info */
 		updateAclDependencies(TypeRelationId, typId, 0,
 							  ownerId,
@@ -5174,3 +5207,119 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
 
 	return result;
 }
+
+/*
+ * Record initial ACL for an extension object
+ *
+ * This will perform a wholesale replacement of the entire ACL for the object
+ * passed in, therefore be sure to pass in the complete new ACL to use.
+ *
+ * Can be called at any time, we check if 'creating_extension' is set and, if
+ * not, exit immediately.
+ *
+ * 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.
+ *
+ * If an ACL already exists for this object/sub-object then we will replace
+ * it with what is passed in.
+ *
+ * Passing in NULL for 'new_acl' will result in the entry for the object being
+ * removed, if one is found.
+ */
+static void
+recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
+{
+	Relation	relation;
+	ScanKeyData key[3];
+	SysScanDesc scan;
+	HeapTuple	tuple;
+	HeapTuple	oldtuple;
+
+	if (!creating_extension)
+		return;
+
+	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_init_privs_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(objoid));
+	ScanKeyInit(&key[1],
+				Anum_pg_init_privs_classoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(classoid));
+	ScanKeyInit(&key[2],
+				Anum_pg_init_privs_objsubid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(objsubid));
+
+	scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
+							  NULL, 3, key);
+
+	/* There should exist only one entry or none. */
+	oldtuple = systable_getnext(scan);
+
+	systable_endscan(scan);
+
+	/* If we find an entry, update it with the latest ACL. */
+	if (HeapTupleIsValid(oldtuple))
+	{
+		Datum		values[Natts_pg_init_privs];
+		bool		nulls[Natts_pg_init_privs];
+		bool		replace[Natts_pg_init_privs];
+
+		/* If we have a new ACL to set, then update the row with it. */
+		if (new_acl)
+		{
+			MemSet(values, 0, sizeof(values));
+			MemSet(nulls, false, sizeof(nulls));
+			MemSet(replace, false, sizeof(replace));
+
+			values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
+			replace[Anum_pg_init_privs_privs - 1] = true;
+
+			oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
+										 values, nulls, replace);
+
+			simple_heap_update(relation, &oldtuple->t_self, oldtuple);
+
+			/* keep the catalog indexes up to date */
+			CatalogUpdateIndexes(relation, oldtuple);
+		}
+		else
+			/* new_acl is NULL, so delete the entry we found. */
+			simple_heap_delete(relation, &oldtuple->t_self);
+	}
+	else
+	{
+		/* No entry found, so add it. */
+		Datum		values[Natts_pg_init_privs];
+		bool		nulls[Natts_pg_init_privs];
+
+		MemSet(nulls, false, sizeof(nulls));
+
+		values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
+		values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
+		values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
+
+		/* This function only handles initial privileges of extensions */
+		values[Anum_pg_init_privs_privtype - 1] =
+			CharGetDatum(INITPRIVS_EXTENSION);
+
+		values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
+
+		tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
+
+		simple_heap_insert(relation, tuple);
+
+		/* keep the catalog indexes up to date */
+		CatalogUpdateIndexes(relation, tuple);
+	}
+
+	/* prevent error when processing objects multiple times */
+	CommandCounterIncrement();
+
+	heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 17f9de1..400cb9f 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -39,6 +39,7 @@
 #include "catalog/pg_extension.h"
 #include "catalog/pg_foreign_data_wrapper.h"
 #include "catalog/pg_foreign_server.h"
+#include "catalog/pg_init_privs.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_namespace.h"
@@ -196,6 +197,7 @@ static bool object_address_present_add_flags(const ObjectAddress *object,
 static bool stack_address_present_add_flags(const ObjectAddress *object,
 								int flags,
 								ObjectAddressStack *stack);
+static void DeleteInitPrivs(const ObjectAddress *object);
 
 
 /*
@@ -1104,12 +1106,13 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
 
 
 	/*
-	 * Delete any comments or security labels associated with this object.
-	 * (This is a convenient place to do these things, rather than having
-	 * every object type know to do it.)
+	 * Delete any comments, security labels, or initial privileges associated
+	 * with this object.  (This is a convenient place to do these things,
+	 * rather than having every object type know to do it.)
 	 */
 	DeleteComments(object->objectId, object->classId, object->objectSubId);
 	DeleteSecurityLabel(object);
+	DeleteInitPrivs(object);
 
 	/*
 	 * CommandCounterIncrement here to ensure that preceding changes are all
@@ -2430,3 +2433,40 @@ getObjectClass(const ObjectAddress *object)
 	elog(ERROR, "unrecognized object class: %u", object->classId);
 	return OCLASS_CLASS;		/* keep compiler quiet */
 }
+
+/*
+ * delete initial ACL for extension objects
+ */
+static void
+DeleteInitPrivs(const ObjectAddress *object)
+{
+	Relation	relation;
+	ScanKeyData key[3];
+	SysScanDesc scan;
+	HeapTuple	oldtuple;
+
+	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_init_privs_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->objectId));
+	ScanKeyInit(&key[1],
+				Anum_pg_init_privs_classoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->classId));
+	ScanKeyInit(&key[2],
+				Anum_pg_init_privs_objsubid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(object->objectSubId));
+
+	scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
+							  NULL, 3, key);
+
+	while (HeapTupleIsValid(oldtuple = systable_getnext(scan)))
+		simple_heap_delete(relation, &oldtuple->t_self);
+
+	systable_endscan(scan);
+
+	heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index ed3ba7b..858667b 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1989,6 +1989,11 @@ setup_dictionary(FILE *cmdfd)
  * Some objects may require different permissions by default, so we
  * make sure we don't overwrite privilege sets that have already been
  * set (NOT NULL).
+ *
+ * Also populate pg_init_privs to save what the privileges are at init
+ * time.  This is used by pg_dump to allow users to change privileges
+ * on catalog objects and to have those privilege changes preserved
+ * across dump/reload and pg_upgrade.
  */
 static void
 setup_privileges(FILE *cmdfd)
@@ -2002,6 +2007,144 @@ setup_privileges(FILE *cmdfd)
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
 		"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        0,"
+		"        relacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_class"
+		"    WHERE"
+		"        relacl IS NOT NULL"
+		"        AND relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        pg_class.oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
+		"        pg_attribute.attnum,"
+		"        pg_attribute.attacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_class"
+		"        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
+		"    WHERE"
+		"        pg_attribute.attacl IS NOT NULL"
+		"        AND pg_class.relkind IN ('r', 'v', 'm', 'S');",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),"
+		"        0,"
+		"        proacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_proc"
+		"    WHERE"
+		"        proacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_type'),"
+		"        0,"
+		"        typacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_type"
+		"    WHERE"
+		"        typacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_language'),"
+		"        0,"
+		"        lanacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_language"
+		"    WHERE"
+		"        lanacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_largeobject_metadata'),"
+		"        0,"
+		"        lomacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_largeobject_metadata"
+		"    WHERE"
+		"        lomacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),"
+		"        0,"
+		"        nspacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_namespace"
+		"    WHERE"
+		"        nspacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_database'),"
+		"        0,"
+		"        datacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_database"
+		"    WHERE"
+		"        datacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE relname = 'pg_tablespace'),"
+		"        0,"
+		"        spcacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_tablespace"
+		"    WHERE"
+		"        spcacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class WHERE "
+		"		  relname = 'pg_foreign_data_wrapper'),"
+		"        0,"
+		"        fdwacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_foreign_data_wrapper"
+		"    WHERE"
+		"        fdwacl IS NOT NULL;",
+		"INSERT INTO pg_init_privs "
+		"  (objoid, classoid, objsubid, initprivs, privtype)"
+		"    SELECT"
+		"        oid,"
+		"        (SELECT oid FROM pg_class "
+		"		  WHERE relname = 'pg_foreign_server'),"
+		"        0,"
+		"        srvacl,"
+		"        'i'"
+		"    FROM"
+		"        pg_foreign_server"
+		"    WHERE"
+		"        srvacl IS NOT NULL;",
 		NULL
 	};
 
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index ab2c1a8..ca5eb3d 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -162,6 +162,9 @@ DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using b
 DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhparent oid_ops));
 #define InheritsParentIndexId  2187
 
+DECLARE_UNIQUE_INDEX(pg_init_privs_o_c_o_index, 3395, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops));
+#define InitPrivsObjIndexId  3395
+
 DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops));
 #define LanguageNameIndexId  2681
 DECLARE_UNIQUE_INDEX(pg_language_oid_index, 2682, on pg_language using btree(oid oid_ops));
diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h
new file mode 100644
index 0000000..e13edd3
--- /dev/null
+++ b/src/include/catalog/pg_init_privs.h
@@ -0,0 +1,101 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_init_privs.h
+ *	  definition of the system "initial privileges" relation (pg_init_privs)
+ *
+ * NOTE: an object is identified by the OID of the row that primarily
+ * defines the object, plus the OID of the table that that row appears in.
+ * For example, a function is identified by the OID of its pg_proc row
+ * plus the pg_class OID of table pg_proc.  This allows unique identification
+ * of objects without assuming that OIDs are unique across tables.
+ *
+ * Since attributes don't have OIDs of their own, we identify an attribute
+ * privilege by the objoid+classoid of its parent table, plus an "objsubid"
+ * giving the attribute column number.  "objsubid" must be zero in a privilege
+ * for a table itself, so that it is distinct from any column privilege.
+ * Currently, objsubid is unused and zero for all other kinds of objects.
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_init_privs.h
+ *
+ * NOTES
+ *		the genbki.pl script reads this file and generates .bki
+ *		information from the DATA() statements.
+ *
+ *		XXX do NOT break up DATA() statements into multiple lines!
+ *			the scripts are not as smart as you might think...
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_INIT_PRIVS_H
+#define PG_INIT_PRIVS_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ *		pg_init_privs definition.  cpp turns this into
+ *		typedef struct FormData_pg_init_privs
+ * ----------------
+ */
+#define InitPrivsRelationId  3394
+
+CATALOG(pg_init_privs,3394) BKI_WITHOUT_OIDS
+{
+	Oid			objoid;			/* OID of object itself */
+	Oid			classoid;		/* OID of table containing object */
+	int32		objsubid;		/* column number, or 0 if not used */
+	char		privtype;		/* from initdb or extension? */
+
+#ifdef CATALOG_VARLEN			/* variable-length fields start here */
+	aclitem		initprivs[1] BKI_FORCE_NOT_NULL;		/* initial privs on
+														 * object */
+#endif
+} FormData_pg_init_privs;
+
+/* ----------------
+ *		Form_pg_init_privs corresponds to a pointer to a tuple with
+ *		the format of pg_init_privs relation.
+ * ----------------
+ */
+typedef FormData_pg_init_privs *Form_pg_init_privs;
+
+/* ----------------
+ *		compiler constants for pg_init_privs
+ * ----------------
+ */
+#define Natts_pg_init_privs				5
+#define Anum_pg_init_privs_objoid		1
+#define Anum_pg_init_privs_classoid		2
+#define Anum_pg_init_privs_objsubid		3
+#define Anum_pg_init_privs_privtype		4
+#define Anum_pg_init_privs_privs		5
+
+/*
+ * It is important to know if the initial privileges are from initdb or from an
+ * extension.  This enum is used to provide that differentiation and the two
+ * places which populate this table (initdb and during CREATE EXTENSION, see
+ * recordExtensionInitPriv()) know to use the correct values.
+ */
+
+typedef enum InitPrivsType
+{
+	INITPRIVS_INITDB = 'i',
+	INITPRIVS_EXTENSION = 'e'
+} InitPrivsType;
+
+/* ----------------
+ *		initial contents of pg_init_privs
+ * ----------------
+ */
+
+/*
+ *	Because the contents of this table depend on what is done with the other
+ *	objects in the system (and, in particular, may change due to changes is
+ *	system_views.sql), there is no initialization here.
+ *
+ *	The initial contents are loaded near the end of initdb.
+ */
+
+#endif   /* PG_INIT_PRIVS_H */
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 2c5be4b..4d81ba7 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -110,6 +110,7 @@ pg_foreign_server|t
 pg_foreign_table|t
 pg_index|t
 pg_inherits|t
+pg_init_privs|t
 pg_language|t
 pg_largeobject|t
 pg_largeobject_metadata|t
-- 
2.5.0


From 545460654892d153a16b59ccb9d0665d9024f7e1 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:31:03 -0400
Subject: [PATCH 2/5] In pg_dump, use a bitmap to represent what to include

pg_dump has historically used a simple boolean 'dump' value to indicate
if a given object should be included in the dump or not.  Instead, use
a bitmap which breaks down the components of an object into their
distinct pieces and use that bitmap to only include the components
requested.

This does not include any behavioral change, but is in preperation for
the change to dump out just ACLs for objects in pg_catalog.
---
 src/bin/pg_dump/common.c  |    2 +-
 src/bin/pg_dump/pg_dump.c | 1502 ++++++++++++++++++++++++---------------------
 src/bin/pg_dump/pg_dump.h |   14 +-
 3 files changed, 833 insertions(+), 685 deletions(-)

diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 373d3bc..1cbb987 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -443,7 +443,7 @@ AssignDumpId(DumpableObject *dobj)
 	dobj->dumpId = ++lastDumpId;
 	dobj->name = NULL;			/* must be set later */
 	dobj->namespace = NULL;		/* may be set later */
-	dobj->dump = true;			/* default assumption */
+	dobj->dump = DUMP_COMPONENT_ALL;	/* default assumption */
 	dobj->ext_member = false;	/* default assumption */
 	dobj->dependencies = NULL;
 	dobj->nDeps = 0;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 454225d..5fa9992 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1287,7 +1287,7 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
 	 * extension contents with something different.
 	 */
 	if (!dopt->binary_upgrade)
-		dobj->dump = false;
+		dobj->dump = DUMP_COMPONENT_NONE;
 	else
 		dobj->dump = ext->dobj.dump;
 
@@ -1309,16 +1309,18 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 * namespaces. If specific namespaces are being dumped, dump just those
 	 * namespaces. Otherwise, dump all non-system namespaces.
 	 */
+
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
 		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
-												   nsinfo->dobj.catId.oid);
+								   nsinfo->dobj.catId.oid) ?
+							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = true;
+		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
@@ -1326,7 +1328,7 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	if (nsinfo->dobj.dump &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = false;
+		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1345,7 +1347,8 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	 */
 	if (table_include_oids.head != NULL)
 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
-												   tbinfo->dobj.catId.oid);
+												   tbinfo->dobj.catId.oid) ?
+								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
 
@@ -1355,7 +1358,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	if (tbinfo->dobj.dump &&
 		simple_oid_list_member(&table_exclude_oids,
 							   tbinfo->dobj.catId.oid))
-		tbinfo->dobj.dump = false;
+		tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1384,7 +1387,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 		if (tytable != NULL)
 			tyinfo->dobj.dump = tytable->dobj.dump;
 		else
-			tyinfo->dobj.dump = false;
+			tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
 		return;
 	}
 
@@ -1404,11 +1407,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	/* dump only types in dumpable namespaces */
-	if (!tyinfo->dobj.namespace->dobj.dump)
-		tyinfo->dobj.dump = false;
-	else
-		tyinfo->dobj.dump = true;
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
 }
 
 /*
@@ -1427,7 +1426,8 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	if (dinfo->dobj.namespace)
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
-		dinfo->dobj.dump = dopt->include_everything;
+		dinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1446,9 +1446,10 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		cast->dobj.dump = false;
+		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		cast->dobj.dump = dopt->include_everything;
+		cast->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1466,9 +1467,10 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
 		return;					/* extension membership overrides all else */
 
 	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		plang->dobj.dump = false;
+		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = dopt->include_everything;
+		plang->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1505,9 +1507,10 @@ static void
 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 {
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = false;
+		extinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		extinfo->dobj.dump = dopt->include_everything;
+		extinfo->dobj.dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1529,7 +1532,8 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	if (dobj->namespace)
 		dobj->dump = dobj->namespace->dobj.dump;
 	else
-		dobj->dump = dopt->include_everything;
+		dobj->dump = dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1934,13 +1938,14 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
 	 * dependency on its table as "special" and pass it to ArchiveEntry now.
 	 * See comments for BuildArchiveDependencies.
 	 */
-	ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
-				 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
-				 NULL, tbinfo->rolname,
-				 false, "TABLE DATA", SECTION_DATA,
-				 "", "", copyStmt,
-				 &(tbinfo->dobj.dumpId), 1,
-				 dumpFn, tdinfo);
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
+					 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
+					 NULL, tbinfo->rolname,
+					 false, "TABLE DATA", SECTION_DATA,
+					 "", "", copyStmt,
+					 &(tbinfo->dobj.dumpId), 1,
+					 dumpFn, tdinfo);
 
 	destroyPQExpBuffer(copyBuf);
 	destroyPQExpBuffer(clistBuf);
@@ -1968,23 +1973,24 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout,
-				 tdinfo->dobj.catId,	/* catalog ID */
-				 tdinfo->dobj.dumpId,	/* dump ID */
-				 tbinfo->dobj.name,		/* Name */
-				 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
-				 NULL,			/* Tablespace */
-				 tbinfo->rolname,		/* Owner */
-				 false,			/* with oids */
-				 "MATERIALIZED VIEW DATA",		/* Desc */
-				 SECTION_POST_DATA,		/* Section */
-				 q->data,		/* Create */
-				 "",			/* Del */
-				 NULL,			/* Copy */
-				 tdinfo->dobj.dependencies,		/* Deps */
-				 tdinfo->dobj.nDeps,	/* # Deps */
-				 NULL,			/* Dumper */
-				 NULL);			/* Dumper Arg */
+	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout,
+					 tdinfo->dobj.catId,	/* catalog ID */
+					 tdinfo->dobj.dumpId,	/* dump ID */
+					 tbinfo->dobj.name,		/* Name */
+					 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
+					 NULL,			/* Tablespace */
+					 tbinfo->rolname,		/* Owner */
+					 false,			/* with oids */
+					 "MATERIALIZED VIEW DATA",		/* Desc */
+					 SECTION_POST_DATA,		/* Section */
+					 q->data,		/* Create */
+					 "",			/* Del */
+					 NULL,			/* Copy */
+					 tdinfo->dobj.dependencies,		/* Deps */
+					 tdinfo->dobj.nDeps,	/* # Deps */
+					 NULL,			/* Dumper */
+					 NULL);			/* Dumper Arg */
 
 	destroyPQExpBuffer(q);
 }
@@ -2000,7 +2006,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids)
 
 	for (i = 0; i < numTables; i++)
 	{
-		if (tblinfo[i].dobj.dump)
+		if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA)
 			makeTableDataInfo(dopt, &(tblinfo[i]), oids);
 	}
 }
@@ -2261,7 +2267,7 @@ guessConstraintInheritance(TableInfo *tblinfo, int numTables)
 			continue;
 
 		/* Don't bother computing anything for non-target tables, either */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		numParents = tbinfo->numParents;
@@ -2811,31 +2817,34 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 					  "SELECT pg_catalog.lo_unlink('%s');\n",
 					  binfo->dobj.name);
 
-	ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
-				 binfo->dobj.name,
-				 NULL, NULL,
-				 binfo->rolname, false,
-				 "BLOB", SECTION_PRE_DATA,
-				 cquery->data, dquery->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
+					 binfo->dobj.name,
+					 NULL, NULL,
+					 binfo->rolname, false,
+					 "BLOB", SECTION_PRE_DATA,
+					 cquery->data, dquery->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* set up tag for comment and/or ACL */
 	resetPQExpBuffer(cquery);
 	appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
 
 	/* Dump comment if any */
-	dumpComment(fout, cquery->data,
-				NULL, binfo->rolname,
-				binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, cquery->data,
+					NULL, binfo->rolname,
+					binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump security label if any */
-	dumpSecLabel(fout, cquery->data,
-				 NULL, binfo->rolname,
-				 binfo->dobj.catId, 0, binfo->dobj.dumpId);
+	if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, cquery->data,
+					 NULL, binfo->rolname,
+					 binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
 	/* Dump ACL if any */
-	if (binfo->blobacl)
+	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
 		dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 				binfo->dobj.name, NULL, cquery->data,
 				NULL, binfo->rolname, binfo->blobacl);
@@ -2956,7 +2965,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
 		TableInfo  *tbinfo = &tblinfo[i];
 
 		/* Ignore row security on tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
 			continue;
 
 		if (g_verbose)
@@ -3096,15 +3105,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 		appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
 						  fmtId(polinfo->dobj.name));
 
-		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-					 polinfo->dobj.name,
-					 polinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "ROW SECURITY", SECTION_POST_DATA,
-					 query->data, "", NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+			ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+						 polinfo->dobj.name,
+						 polinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "ROW SECURITY", SECTION_POST_DATA,
+						 query->data, "", NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
 		destroyPQExpBuffer(query);
 		return;
@@ -3147,15 +3157,16 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 	appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
 	appendPQExpBuffer(delqry, " ON %s;\n", fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-				 polinfo->dobj.name,
-				 polinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "POLICY", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
+					 polinfo->dobj.name,
+					 polinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "POLICY", SECTION_POST_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -3760,7 +3771,8 @@ getTypes(Archive *fout, int *numTypes)
 		 */
 		tyinfo[i].nDomChecks = 0;
 		tyinfo[i].domChecks = NULL;
-		if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			tyinfo[i].typtype == TYPTYPE_DOMAIN)
 			getDomainConstraints(fout, &(tyinfo[i]));
 
 		/*
@@ -3773,8 +3785,9 @@ getTypes(Archive *fout, int *numTypes)
 		 * should copy the base type's catId, but then it might capture the
 		 * pg_depend entries for the type, which we don't want.
 		 */
-		if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
-									tyinfo[i].typtype == TYPTYPE_RANGE))
+		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
+			(tyinfo[i].typtype == TYPTYPE_BASE ||
+			 tyinfo[i].typtype == TYPTYPE_RANGE))
 		{
 			stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
 			stinfo->dobj.objType = DO_SHELL_TYPE;
@@ -3790,7 +3803,7 @@ getTypes(Archive *fout, int *numTypes)
 			 * dump it if the I/O or canonicalize functions need to be dumped;
 			 * this is taken care of while sorting dependencies.
 			 */
-			stinfo->dobj.dump = false;
+			stinfo->dobj.dump = DUMP_COMPONENT_NONE;
 
 			/*
 			 * However, if dumping from pre-7.3, there will be no dependency
@@ -3808,7 +3821,7 @@ getTypes(Archive *fout, int *numTypes)
 				typoutput = atooid(PQgetvalue(res, i, i_typoutput));
 
 				funcInfo = findFuncByOid(typinput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3817,11 +3830,11 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 
 				funcInfo = findFuncByOid(typoutput);
-				if (funcInfo && funcInfo->dobj.dump)
+				if (funcInfo && funcInfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 				{
 					/* base type depends on function */
 					addObjectDependency(&tyinfo[i].dobj,
@@ -3830,7 +3843,7 @@ getTypes(Archive *fout, int *numTypes)
 					addObjectDependency(&funcInfo->dobj,
 										stinfo->dobj.dumpId);
 					/* mark shell type as to be dumped */
-					stinfo->dobj.dump = true;
+					stinfo->dobj.dump = DUMP_COMPONENT_ALL;
 				}
 			}
 		}
@@ -5353,10 +5366,11 @@ getTables(Archive *fout, int *numTables)
 		 * Decide whether we want to dump this table.
 		 */
 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
-			tblinfo[i].dobj.dump = false;
+			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
 		else
 			selectDumpableTable(&tblinfo[i], dopt);
-		tblinfo[i].interesting = tblinfo[i].dobj.dump;
+
+		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
 
@@ -5423,13 +5437,13 @@ getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
 
 		if (!OidIsValid(seqinfo->owning_tab))
 			continue;			/* not an owned sequence */
-		if (seqinfo->dobj.dump)
+		if (seqinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
 			continue;			/* no need to search */
 		owning_tab = findTableByOid(seqinfo->owning_tab);
 		if (owning_tab && owning_tab->dobj.dump)
 		{
 			seqinfo->interesting = true;
-			seqinfo->dobj.dump = true;
+			seqinfo->dobj.dump = DUMP_COMPONENT_ALL;
 		}
 	}
 }
@@ -5531,8 +5545,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 		if (!tbinfo->hasindex)
 			continue;
 
-		/* Ignore indexes of tables not to be dumped */
-		if (!tbinfo->dobj.dump)
+		/* Ignore indexes of tables whose definitions are not to be dumped */
+		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -5899,7 +5913,8 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -6238,7 +6253,8 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 	{
 		TableInfo  *tbinfo = &tblinfo[i];
 
-		if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
+		if (!tbinfo->hastriggers ||
+			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
 		if (g_verbose)
@@ -8591,12 +8607,13 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
 			dumpBlob(fout, (BlobInfo *) dobj);
 			break;
 		case DO_BLOB_DATA:
-			ArchiveEntry(fout, dobj->catId, dobj->dumpId,
-						 dobj->name, NULL, NULL, "",
-						 false, "BLOBS", SECTION_DATA,
-						 "", "", NULL,
-						 NULL, 0,
-						 dumpBlobs, NULL);
+			if (dobj->dump & DUMP_COMPONENT_DATA)
+				ArchiveEntry(fout, dobj->catId, dobj->dumpId,
+							 dobj->name, NULL, NULL, "",
+							 false, "BLOBS", SECTION_DATA,
+							 "", "", NULL,
+							 NULL, 0,
+							 dumpBlobs, NULL);
 			break;
 		case DO_POLICY:
 			dumpPolicy(fout, (PolicyInfo *) dobj);
@@ -8644,26 +8661,31 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
-				 nspinfo->dobj.name,
-				 NULL, NULL,
-				 nspinfo->rolname,
-				 false, "SCHEMA", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
+					 nspinfo->dobj.name,
+					 NULL, NULL,
+					 nspinfo->rolname,
+					 false, "SCHEMA", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Schema Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, nspinfo->rolname,
-				nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, nspinfo->rolname,
-				 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, nspinfo->rolname,
+					nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
 
-	dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
-			qnspname, NULL, nspinfo->dobj.name, NULL,
-			nspinfo->rolname, nspinfo->nspacl);
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, nspinfo->rolname,
+					 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+
+	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
+				qnspname, NULL, nspinfo->dobj.name, NULL,
+				nspinfo->rolname, nspinfo->nspacl);
 
 	free(qnspname);
 
@@ -8773,22 +8795,26 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
 	appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
 
-	ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
-				 extinfo->dobj.name,
-				 NULL, NULL,
-				 "",
-				 false, "EXTENSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
+					 extinfo->dobj.name,
+					 NULL, NULL,
+					 "",
+					 false, "EXTENSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Extension Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+	if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
+
+	if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
 
 	free(qextname);
 
@@ -8928,28 +8954,33 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9061,28 +9092,33 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9131,28 +9167,33 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -9520,28 +9561,33 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9683,28 +9729,33 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "DOMAIN", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "DOMAIN", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Domain Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	/* Dump any per-constraint comments */
 	for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9716,10 +9767,13 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 						  fmtId(domcheck->dobj.name));
 		appendPQExpBuffer(labelq, "ON DOMAIN %s",
 						  qtypname);
-		dumpComment(fout, labelq->data,
-					tyinfo->dobj.namespace->dobj.name,
-					tyinfo->rolname,
-					domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+		if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpComment(fout, labelq->data,
+						tyinfo->dobj.namespace->dobj.name,
+						tyinfo->rolname,
+						domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
+
 		destroyPQExpBuffer(labelq);
 	}
 
@@ -9909,29 +9963,34 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-				 tyinfo->dobj.name,
-				 tyinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tyinfo->rolname, false,
-				 "TYPE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+					 tyinfo->dobj.name,
+					 tyinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tyinfo->rolname, false,
+					 "TYPE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Type Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
-				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
-	dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
-			qtypname, NULL, tyinfo->dobj.name,
-			tyinfo->dobj.namespace->dobj.name,
-			tyinfo->rolname, tyinfo->typacl);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
+				qtypname, NULL, tyinfo->dobj.name,
+				tyinfo->dobj.namespace->dobj.name,
+				tyinfo->rolname, tyinfo->typacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9941,7 +10000,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 	destroyPQExpBuffer(query);
 
 	/* Dump any per-column comments */
-	dumpCompositeTypeColComments(fout, tyinfo);
+	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpCompositeTypeColComments(fout, tyinfo);
 }
 
 /*
@@ -10086,15 +10146,16 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
 					  fmtId(stinfo->dobj.name));
 
-	ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
-				 stinfo->dobj.name,
-				 stinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 stinfo->baseType->rolname, false,
-				 "SHELL TYPE", SECTION_PRE_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
+					 stinfo->dobj.name,
+					 stinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 stinfo->baseType->rolname, false,
+					 "SHELL TYPE", SECTION_PRE_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 }
@@ -10223,23 +10284,27 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
 
-	ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
-				 plang->dobj.name,
-				 lanschema, NULL, plang->lanowner,
-				 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
+					 plang->dobj.name,
+					 lanschema, NULL, plang->lanowner,
+					 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Proc Lang Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				plang->dobj.catId, 0, plang->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 NULL, "",
-				 plang->dobj.catId, 0, plang->dobj.dumpId);
+	if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					plang->dobj.catId, 0, plang->dobj.dumpId);
+
+	if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 NULL, "",
+					 plang->dobj.catId, 0, plang->dobj.dumpId);
 
-	if (plang->lanpltrusted)
+	if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 				qlanname, NULL, plang->dobj.name,
 				lanschema,
@@ -10888,28 +10953,33 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
-				 funcsig_tag,
-				 finfo->dobj.namespace->dobj.name,
-				 NULL,
-				 finfo->rolname, false,
-				 "FUNCTION", SECTION_PRE_DATA,
-				 q->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
+					 funcsig_tag,
+					 finfo->dobj.namespace->dobj.name,
+					 NULL,
+					 finfo->rolname, false,
+					 "FUNCTION", SECTION_PRE_DATA,
+					 q->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Function Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				finfo->dobj.namespace->dobj.name, finfo->rolname,
-				finfo->dobj.catId, 0, finfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 finfo->dobj.namespace->dobj.name, finfo->rolname,
-				 finfo->dobj.catId, 0, finfo->dobj.dumpId);
+	if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					finfo->dobj.namespace->dobj.name, finfo->rolname,
+					finfo->dobj.catId, 0, finfo->dobj.dumpId);
 
-	dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
-			funcsig, NULL, funcsig_tag,
-			finfo->dobj.namespace->dobj.name,
-			finfo->rolname, finfo->proacl);
+	if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 finfo->dobj.namespace->dobj.name, finfo->rolname,
+					 finfo->dobj.catId, 0, finfo->dobj.dumpId);
+
+	if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
+				funcsig, NULL, funcsig_tag,
+				finfo->dobj.namespace->dobj.name,
+				finfo->rolname, finfo->proacl);
 
 	PQclear(res);
 
@@ -11018,18 +11088,20 @@ dumpCast(Archive *fout, CastInfo *cast)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
 
-	ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "CAST", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "CAST", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Cast Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				cast->dobj.catId, 0, cast->dobj.dumpId);
+	if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					cast->dobj.catId, 0, cast->dobj.dumpId);
 
 	free(sourceType);
 	free(targetType);
@@ -11138,18 +11210,20 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(defqry, &transform->dobj, labelq->data);
 
-	ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
-				 labelq->data,
-				 "pg_catalog", NULL, "",
-				 false, "TRANSFORM", SECTION_PRE_DATA,
-				 defqry->data, delqry->data, NULL,
-				 transform->dobj.dependencies, transform->dobj.nDeps,
-				 NULL, NULL);
+	if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
+					 labelq->data,
+					 "pg_catalog", NULL, "",
+					 false, "TRANSFORM", SECTION_PRE_DATA,
+					 defqry->data, delqry->data, NULL,
+					 transform->dobj.dependencies, transform->dobj.nDeps,
+					 NULL, NULL);
 
 	/* Dump Transform Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				transform->dobj.catId, 0, transform->dobj.dumpId);
+	if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					transform->dobj.catId, 0, transform->dobj.dumpId);
 
 	free(lanname);
 	free(transformType);
@@ -11392,20 +11466,22 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
-				 oprinfo->dobj.name,
-				 oprinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 oprinfo->rolname,
-				 false, "OPERATOR", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
+					 oprinfo->dobj.name,
+					 oprinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 oprinfo->rolname,
+					 false, "OPERATOR", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Comments */
-	dumpComment(fout, labelq->data,
-				oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
-				oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
+	if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
+					oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -11970,20 +12046,22 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
-				 opcinfo->dobj.name,
-				 opcinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opcinfo->rolname,
-				 false, "OPERATOR CLASS", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
+					 opcinfo->dobj.name,
+					 opcinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opcinfo->rolname,
+					 false, "OPERATOR CLASS", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Class Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opcinfo->rolname,
-				opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
+	if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opcinfo->rolname,
+					opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
 
 	free(amname);
 	destroyPQExpBuffer(query);
@@ -12284,20 +12362,22 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
-				 opfinfo->dobj.name,
-				 opfinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 opfinfo->rolname,
-				 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
+					 opfinfo->dobj.name,
+					 opfinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 opfinfo->rolname,
+					 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Operator Family Comments */
-	dumpComment(fout, labelq->data,
-				NULL, opfinfo->rolname,
-				opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
+	if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, opfinfo->rolname,
+					opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
 
 	free(amname);
 	PQclear(res_ops);
@@ -12374,20 +12454,22 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
-				 collinfo->dobj.name,
-				 collinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 collinfo->rolname,
-				 false, "COLLATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
+					 collinfo->dobj.name,
+					 collinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 collinfo->rolname,
+					 false, "COLLATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Collation Comments */
-	dumpComment(fout, labelq->data,
-				collinfo->dobj.namespace->dobj.name, collinfo->rolname,
-				collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
+	if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					collinfo->dobj.namespace->dobj.name, collinfo->rolname,
+					collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12474,20 +12556,22 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
-				 convinfo->dobj.name,
-				 convinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 convinfo->rolname,
-				 false, "CONVERSION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
+					 convinfo->dobj.name,
+					 convinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 convinfo->rolname,
+					 false, "CONVERSION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Conversion Comments */
-	dumpComment(fout, labelq->data,
-				convinfo->dobj.namespace->dobj.name, convinfo->rolname,
-				convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
+	if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					convinfo->dobj.namespace->dobj.name, convinfo->rolname,
+					convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -12937,23 +13021,30 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
 
-	ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-				 aggsig_tag,
-				 agginfo->aggfn.dobj.namespace->dobj.name,
-				 NULL,
-				 agginfo->aggfn.rolname,
-				 false, "AGGREGATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
+					 agginfo->aggfn.dobj.dumpId,
+					 aggsig_tag,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 NULL,
+					 agginfo->aggfn.rolname,
+					 false, "AGGREGATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Aggregate Comments */
-	dumpComment(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
-				 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					agginfo->aggfn.dobj.namespace->dobj.name,
+					agginfo->aggfn.rolname,
+					agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 agginfo->aggfn.dobj.namespace->dobj.name,
+					 agginfo->aggfn.rolname,
+					 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
 	/*
 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
@@ -12966,11 +13057,12 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	aggsig = format_function_signature(fout, &agginfo->aggfn, true);
 	aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
 
-	dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
-			"FUNCTION",
-			aggsig, NULL, aggsig_tag,
-			agginfo->aggfn.dobj.namespace->dobj.name,
-			agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
+				"FUNCTION",
+				aggsig, NULL, aggsig_tag,
+				agginfo->aggfn.dobj.namespace->dobj.name,
+				agginfo->aggfn.rolname, agginfo->aggfn.proacl);
 
 	free(aggsig);
 	if (aggfullsig)
@@ -13038,20 +13130,22 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
-				 prsinfo->dobj.name,
-				 prsinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
+					 prsinfo->dobj.name,
+					 prsinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Parser Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
+	if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13126,20 +13220,22 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
-				 dictinfo->dobj.name,
-				 dictinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 dictinfo->rolname,
-				 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
+					 dictinfo->dobj.name,
+					 dictinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 dictinfo->rolname,
+					 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Dictionary Comments */
-	dumpComment(fout, labelq->data,
-				NULL, dictinfo->rolname,
-				dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
+	if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, dictinfo->rolname,
+					dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13193,20 +13289,22 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
-				 tmplinfo->dobj.name,
-				 tmplinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 "",
-				 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
+					 tmplinfo->dobj.name,
+					 tmplinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 "",
+					 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Template Comments */
-	dumpComment(fout, labelq->data,
-				NULL, "",
-				tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
+	if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, "",
+					tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13322,20 +13420,22 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
-				 cfginfo->dobj.name,
-				 cfginfo->dobj.namespace->dobj.name,
-				 NULL,
-				 cfginfo->rolname,
-				 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
+					 cfginfo->dobj.name,
+					 cfginfo->dobj.namespace->dobj.name,
+					 NULL,
+					 cfginfo->rolname,
+					 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump Configuration Comments */
-	dumpComment(fout, labelq->data,
-				NULL, cfginfo->rolname,
-				cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
+	if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, cfginfo->rolname,
+					cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -13389,27 +13489,30 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-				 fdwinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 fdwinfo->rolname,
-				 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+					 fdwinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 fdwinfo->rolname,
+					 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-			"FOREIGN DATA WRAPPER",
-			qfdwname, NULL, fdwinfo->dobj.name,
-			NULL, fdwinfo->rolname,
-			fdwinfo->fdwacl);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+				"FOREIGN DATA WRAPPER",
+				qfdwname, NULL, fdwinfo->dobj.name,
+				NULL, fdwinfo->rolname,
+				fdwinfo->fdwacl);
 
 	/* Dump Foreign Data Wrapper Comments */
-	dumpComment(fout, labelq->data,
-				NULL, fdwinfo->rolname,
-				fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
+	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, fdwinfo->rolname,
+					fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
 
 	free(qfdwname);
 
@@ -13482,33 +13585,37 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-				 srvinfo->dobj.name,
-				 NULL,
-				 NULL,
-				 srvinfo->rolname,
-				 false, "SERVER", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+					 srvinfo->dobj.name,
+					 NULL,
+					 NULL,
+					 srvinfo->rolname,
+					 false, "SERVER", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Handle the ACL */
-	dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-			"FOREIGN SERVER",
-			qsrvname, NULL, srvinfo->dobj.name,
-			NULL, srvinfo->rolname,
-			srvinfo->srvacl);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+				"FOREIGN SERVER",
+				qsrvname, NULL, srvinfo->dobj.name,
+				NULL, srvinfo->rolname,
+				srvinfo->srvacl);
 
 	/* Dump user mappings */
-	dumpUserMappings(fout,
-					 srvinfo->dobj.name, NULL,
-					 srvinfo->rolname,
-					 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
+		dumpUserMappings(fout,
+						 srvinfo->dobj.name, NULL,
+						 srvinfo->rolname,
+						 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
 
 	/* Dump Foreign Server Comments */
-	dumpComment(fout, labelq->data,
-				NULL, srvinfo->rolname,
-				srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
+	if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, srvinfo->rolname,
+					srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
 
 	free(qsrvname);
 
@@ -13671,15 +13778,16 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 		exit_horribly(NULL, "could not parse default ACL list (%s)\n",
 					  daclinfo->defaclacl);
 
-	ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
-				 tag->data,
+	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
+		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
+					 tag->data,
 	   daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
-				 NULL,
-				 daclinfo->defaclrole,
-				 false, "DEFAULT ACL", SECTION_POST_DATA,
-				 q->data, "", NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 NULL,
+					 daclinfo->defaclrole,
+					 false, "DEFAULT ACL", SECTION_POST_DATA,
+					 q->data, "", NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(tag);
 	destroyPQExpBuffer(q);
@@ -14048,19 +14156,16 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
 static void
 dumpTable(Archive *fout, TableInfo *tbinfo)
 {
-	DumpOptions *dopt = fout->dopt;
-
-	if (tbinfo->dobj.dump && !dopt->dataOnly)
-	{
-		char	   *namecopy;
+	char		   *namecopy;
 
-		if (tbinfo->relkind == RELKIND_SEQUENCE)
-			dumpSequence(fout, tbinfo);
-		else
-			dumpTableSchema(fout, tbinfo);
+	if (tbinfo->relkind == RELKIND_SEQUENCE)
+		dumpSequence(fout, tbinfo);
+	else
+		dumpTableSchema(fout, tbinfo);
 
-		/* Handle the ACL here */
-		namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	/* Handle the ACL here */
+	namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 				(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
 				"TABLE",
@@ -14068,47 +14173,49 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 				tbinfo->relacl);
 
-		/*
-		 * Handle column ACLs, if any.  Note: we pull these with a separate
-		 * query rather than trying to fetch them during getTableAttrs, so
-		 * that we won't miss ACLs on system columns.
-		 */
-		if (fout->remoteVersion >= 80400)
-		{
-			PQExpBuffer query = createPQExpBuffer();
-			PGresult   *res;
-			int			i;
+	/*
+	 * Handle column ACLs, if any.  Note: we pull these with a separate
+	 * query rather than trying to fetch them during getTableAttrs, so
+	 * that we won't miss ACLs on system columns.
+	 */
+	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
+	{
+		PQExpBuffer query = createPQExpBuffer();
+		PGresult   *res;
+		int			i;
 
-			appendPQExpBuffer(query,
-					   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
-							  "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
-							  "ORDER BY attnum",
-							  tbinfo->dobj.catId.oid);
-			res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+		appendPQExpBuffer(query,
+				   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
+						  "WHERE attrelid = '%u' AND NOT attisdropped "
+						  "AND attacl IS NOT NULL "
+						  "ORDER BY attnum",
+						  tbinfo->dobj.catId.oid);
+		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
-			for (i = 0; i < PQntuples(res); i++)
-			{
-				char	   *attname = PQgetvalue(res, i, 0);
-				char	   *attacl = PQgetvalue(res, i, 1);
-				char	   *attnamecopy;
-				char	   *acltag;
-
-				attnamecopy = pg_strdup(fmtId(attname));
-				acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
-				/* Column's GRANT type is always TABLE */
-				dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
-						namecopy, attnamecopy, acltag,
-						tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-						attacl);
-				free(attnamecopy);
-				free(acltag);
-			}
-			PQclear(res);
-			destroyPQExpBuffer(query);
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			char	   *attname = PQgetvalue(res, i, 0);
+			char	   *attacl = PQgetvalue(res, i, 1);
+			char	   *attnamecopy;
+			char	   *acltag;
+
+			attnamecopy = pg_strdup(fmtId(attname));
+			acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
+			/* Column's GRANT type is always TABLE */
+			dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
+					namecopy, attnamecopy, acltag,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					attacl);
+			free(attnamecopy);
+			free(acltag);
 		}
-
-		free(namecopy);
+		PQclear(res);
+		destroyPQExpBuffer(query);
 	}
+
+	free(namecopy);
+
+	return;
 }
 
 /*
@@ -14786,24 +14893,28 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 	if (dopt->binary_upgrade)
 		binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
 			(tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
-				 tbinfo->rolname,
+					 tbinfo->rolname,
 			   (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
-				 reltypename,
-				 tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+					 reltypename,
+					 tbinfo->postponed_def ?
+						SECTION_POST_DATA : SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 
 	/* Dump Table Comments */
-	dumpTableComment(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpTableComment(fout, tbinfo, reltypename);
 
 	/* Dump Table Security Labels */
-	dumpTableSecLabel(fout, tbinfo, reltypename);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpTableSecLabel(fout, tbinfo, reltypename);
 
 	/* Dump comments on inlined table constraints */
 	for (j = 0; j < tbinfo->ncheck; j++)
@@ -14813,7 +14924,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		if (constr->separate || !constr->conislocal)
 			continue;
 
-		dumpTableConstraintComment(fout, constr);
+		if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+			dumpTableConstraintComment(fout, constr);
 	}
 
 	destroyPQExpBuffer(q);
@@ -14860,15 +14972,16 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 	appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
 					  fmtId(tbinfo->attnames[adnum - 1]));
 
-	ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
-				 tbinfo->attnames[adnum - 1],
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "DEFAULT", SECTION_PRE_DATA,
-				 q->data, delq->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
+					 tbinfo->attnames[adnum - 1],
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "DEFAULT", SECTION_PRE_DATA,
+					 q->data, delq->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -14975,24 +15088,26 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 		appendPQExpBuffer(delq, "%s;\n",
 						  fmtId(indxinfo->dobj.name));
 
-		ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
-					 indxinfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "INDEX", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
+						 indxinfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "INDEX", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 
 	/* Dump Index Comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				indxinfo->dobj.catId, 0,
-				is_constraint ? indxinfo->indexconstraint :
-				indxinfo->dobj.dumpId);
+	if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					indxinfo->dobj.catId, 0,
+					is_constraint ? indxinfo->indexconstraint :
+					indxinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -15103,15 +15218,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 indxinfo->tablespace,
-					 tbinfo->rolname, false,
-					 "CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 indxinfo->tablespace,
+						 tbinfo->rolname, false,
+						 "CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'f')
 	{
@@ -15136,15 +15252,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 						  fmtId(coninfo->dobj.name));
 
-		ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-					 coninfo->dobj.name,
-					 tbinfo->dobj.namespace->dobj.name,
-					 NULL,
-					 tbinfo->rolname, false,
-					 "FK CONSTRAINT", SECTION_POST_DATA,
-					 q->data, delq->data, NULL,
-					 NULL, 0,
-					 NULL, NULL);
+		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+						 coninfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "FK CONSTRAINT", SECTION_POST_DATA,
+						 q->data, delq->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 	}
 	else if (coninfo->contype == 'c' && tbinfo)
 	{
@@ -15171,15 +15288,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else if (coninfo->contype == 'c' && tbinfo == NULL)
@@ -15207,15 +15325,16 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 							  fmtId(coninfo->dobj.name));
 
-			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-						 coninfo->dobj.name,
-						 tyinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tyinfo->rolname, false,
-						 "CHECK CONSTRAINT", SECTION_POST_DATA,
-						 q->data, delq->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
+							 coninfo->dobj.name,
+							 tyinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tyinfo->rolname, false,
+							 "CHECK CONSTRAINT", SECTION_POST_DATA,
+							 q->data, delq->data, NULL,
+							 NULL, 0,
+							 NULL, NULL);
 		}
 	}
 	else
@@ -15225,7 +15344,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 	}
 
 	/* Dump Constraint Comments --- only works for table constraints */
-	if (tbinfo && coninfo->separate)
+	if (tbinfo && coninfo->separate &&
+		coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
 		dumpTableConstraintComment(fout, coninfo);
 
 	destroyPQExpBuffer(q);
@@ -15249,10 +15369,12 @@ dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
 					  fmtId(coninfo->dobj.name));
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				coninfo->dobj.catId, 0,
+
+	if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					coninfo->dobj.catId, 0,
 			 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(labelq);
@@ -15447,15 +15569,16 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 		binary_upgrade_extension_member(query, &tbinfo->dobj,
 										labelq->data);
 
-	ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE", SECTION_PRE_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE", SECTION_PRE_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/*
 	 * If the sequence is owned by a table column, emit the ALTER for it as a
@@ -15483,25 +15606,29 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 			appendPQExpBuffer(query, ".%s;\n",
 						fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
 
-			ArchiveEntry(fout, nilCatalogId, createDumpId(),
-						 tbinfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname,
-						 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
-						 query->data, "", NULL,
-						 &(tbinfo->dobj.dumpId), 1,
-						 NULL, NULL);
+			if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+				ArchiveEntry(fout, nilCatalogId, createDumpId(),
+							 tbinfo->dobj.name,
+							 tbinfo->dobj.namespace->dobj.name,
+							 NULL,
+							 tbinfo->rolname,
+							 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
+							 query->data, "", NULL,
+							 &(tbinfo->dobj.dumpId), 1,
+							 NULL, NULL);
 		}
 	}
 
 	/* Dump Sequence Comments and Security Labels */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
-	dumpSecLabel(fout, labelq->data,
-				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
+		dumpSecLabel(fout, labelq->data,
+					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -15550,15 +15677,16 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 	appendPQExpBuffer(query, ", %s, %s);\n",
 					  last, (called ? "true" : "false"));
 
-	ArchiveEntry(fout, nilCatalogId, createDumpId(),
-				 tbinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname,
-				 false, "SEQUENCE SET", SECTION_DATA,
-				 query->data, "", NULL,
-				 &(tbinfo->dobj.dumpId), 1,
-				 NULL, NULL);
+	if (tbinfo->dobj.dump & DUMP_COMPONENT_DATA)
+		ArchiveEntry(fout, nilCatalogId, createDumpId(),
+					 tbinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname,
+					 false, "SEQUENCE SET", SECTION_DATA,
+					 query->data, "", NULL,
+					 &(tbinfo->dobj.dumpId), 1,
+					 NULL, NULL);
 
 	PQclear(res);
 
@@ -15757,19 +15885,21 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 	appendPQExpBuffer(labelq, "ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
-				 tginfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "TRIGGER", SECTION_POST_DATA,
-				 query->data, delqry->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+			ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
+						 tginfo->dobj.name,
+						 tbinfo->dobj.namespace->dobj.name,
+						 NULL,
+						 tbinfo->rolname, false,
+						 "TRIGGER", SECTION_POST_DATA,
+						 query->data, delqry->data, NULL,
+						 NULL, 0,
+						 NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
+	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+					tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
@@ -15834,14 +15964,16 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
 	appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
 					  fmtId(evtinfo->dobj.name));
 
-	ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
-				 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
-				 "EVENT TRIGGER", SECTION_POST_DATA,
-				 query->data, "", NULL, NULL, 0, NULL, NULL);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
+					 evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
+					 "EVENT TRIGGER", SECTION_POST_DATA,
+					 query->data, "", NULL, NULL, 0, NULL, NULL);
 
-	dumpComment(fout, labelq->data,
-				NULL, evtinfo->evtowner,
-				evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
+	if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					NULL, evtinfo->evtowner,
+					evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
 
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(labelq);
@@ -15958,21 +16090,23 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 	appendPQExpBuffer(labelq, " ON %s",
 					  fmtId(tbinfo->dobj.name));
 
-	ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
-				 rinfo->dobj.name,
-				 tbinfo->dobj.namespace->dobj.name,
-				 NULL,
-				 tbinfo->rolname, false,
-				 "RULE", SECTION_POST_DATA,
-				 cmd->data, delcmd->data, NULL,
-				 NULL, 0,
-				 NULL, NULL);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
+					 rinfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "RULE", SECTION_POST_DATA,
+					 cmd->data, delcmd->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	/* Dump rule comments */
-	dumpComment(fout, labelq->data,
-				tbinfo->dobj.namespace->dobj.name,
-				tbinfo->rolname,
-				rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
+	if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, labelq->data,
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->rolname,
+					rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
 
 	PQclear(res);
 
@@ -16146,7 +16280,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 			{
 				TableInfo  *configtbl;
 				Oid			configtbloid = atooid(extconfigarray[j]);
-				bool		dumpobj = curext->dobj.dump;
+				bool		dumpobj =
+								curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
 
 				configtbl = findTableByOid(configtbloid);
 				if (configtbl == NULL)
@@ -16156,7 +16291,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 				 * Tables of not-to-be-dumped extensions shouldn't be dumped
 				 * unless the table or its schema is explicitly included
 				 */
-				if (!curext->dobj.dump)
+				if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
 				{
 					/* check table explicitly requested */
 					if (table_include_oids.head != NULL &&
@@ -16165,7 +16300,8 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 						dumpobj = true;
 
 					/* check table's schema explicitly requested */
-					if (configtbl->dobj.namespace->dobj.dump)
+					if (configtbl->dobj.namespace->dobj.dump &
+							DUMP_COMPONENT_DATA)
 						dumpobj = true;
 				}
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index c02c536..f479c06 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -81,6 +81,18 @@ typedef enum
 	DO_POLICY
 } DumpableObjectType;
 
+/* component types of an object which can be selected for dumping */
+typedef uint32 DumpComponents;	/* a bitmask of dump object components */
+#define DUMP_COMPONENT_NONE			(0)
+#define DUMP_COMPONENT_DEFINITION	(1 << 0)
+#define DUMP_COMPONENT_DATA			(1 << 1)
+#define DUMP_COMPONENT_COMMENT		(1 << 2)
+#define DUMP_COMPONENT_SECLABEL		(1 << 3)
+#define DUMP_COMPONENT_ACL			(1 << 4)
+#define DUMP_COMPONENT_POLICY		(1 << 5)
+#define DUMP_COMPONENT_USERMAP		(1 << 6)
+#define DUMP_COMPONENT_ALL			(0xFFFF)
+
 typedef struct _dumpableObject
 {
 	DumpableObjectType objType;
@@ -88,7 +100,7 @@ typedef struct _dumpableObject
 	DumpId		dumpId;			/* assigned by AssignDumpId() */
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
-	bool		dump;			/* true if we want to dump this object */
+	DumpComponents dump;	/* bitmask of components to dump */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From 1968c2c7dd3950c824453ac9dac0049382aab30f Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 11:44:21 -0400
Subject: [PATCH 3/5] In pg_dump, split "dump" into "dump" and "dump_contains"

Historically, the "dump" component of the namespace has been used
to decide if the objects inside of the namespace should be dumped
also.  Given that "dump" is now a bitmask and may be partial, and
we may want to dump out all components of the namespace object but
only some of the components of objects contained in the namespace,
create a "dump_contains" bitmask which will represent what components
of the objects inside of a namespace should be dumped out.

No behavior change here, but in preparation for a change where we
will dump out just the ACLs of objects in pg_catalog, but we might
not dump out the ACL of the pg_catalog namespace itself (for instance,
when it hasn't been changed from the value set at initdb time).
---
 src/bin/pg_dump/pg_dump.c | 21 ++++++++++++---------
 src/bin/pg_dump/pg_dump.h |  3 ++-
 2 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 5fa9992..650c17a 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1311,24 +1311,25 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 	 */
 
 	if (table_include_oids.head != NULL)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else if (schema_include_oids.head != NULL)
-		nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
+			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
 							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
 
 	/*
 	 * In any case, a namespace can be excluded by an exclusion switch
 	 */
-	if (nsinfo->dobj.dump &&
+	if (nsinfo->dobj.dump_contains &&
 		simple_oid_list_member(&schema_exclude_oids,
 							   nsinfo->dobj.catId.oid))
-		nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1350,7 +1351,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 												   tbinfo->dobj.catId.oid) ?
 								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
-		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
+		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
 
 	/*
 	 * In any case, a table can be excluded by an exclusion switch
@@ -1407,7 +1408,8 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 	if (checkExtensionMembership(&tyinfo->dobj, dopt))
 		return;					/* extension membership overrides all else */
 
-	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump;
+	/* Dump based on if the contents of the namespace are being dumped */
+	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
 }
 
 /*
@@ -1424,6 +1426,7 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 	/* Default ACLs can't be extension members */
 
 	if (dinfo->dobj.namespace)
+		/* default ACLs are considered part of the namespace */
 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 	else
 		dinfo->dobj.dump = dopt->include_everything ?
@@ -1530,7 +1533,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	 * non-namespace-associated items, dump if we're dumping "everything".
 	 */
 	if (dobj->namespace)
-		dobj->dump = dobj->namespace->dobj.dump;
+		dobj->dump = dobj->namespace->dobj.dump_contains;
 	else
 		dobj->dump = dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index f479c06..85f9f48 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -100,7 +100,8 @@ typedef struct _dumpableObject
 	DumpId		dumpId;			/* assigned by AssignDumpId() */
 	char	   *name;			/* object name (should never be NULL) */
 	struct _namespaceInfo *namespace;	/* containing namespace, or NULL */
-	DumpComponents dump;	/* bitmask of components to dump */
+	DumpComponents dump;		/* bitmask of components to dump */
+	DumpComponents dump_contains;		/* as above, but for contained objects */
 	bool		ext_member;		/* true if object is member of extension */
 	DumpId	   *dependencies;	/* dumpIds of objects this one depends on */
 	int			nDeps;			/* number of valid dependencies */
-- 
2.5.0


From 0add15144a5d5f8ca451423332d2d1b0c4545e70 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 13 Mar 2016 12:43:24 -0400
Subject: [PATCH 4/5] In pg_dump, include pg_catalog and extension ACLs, if
 changed

Now that all of the infrastructure exists, add in the ability to
dump out the ACLs of the objects inside of pg_catalog or the ACLs
for objects which are members of extensions, but only if they have
been changed from their original values.

The original values are tracked in pg_init_privs.  When pg_dump'ing
9.6-and-above databases, we will dump out the ACLs for all objects
in pg_catalog and the ACLs for all extension members, where the ACL
has been changed from the original value which was set during either
initdb or CREATE EXTENSION.

This should not change dumps against pre-9.6 databases.
---
 doc/src/sgml/extend.sgml                   |   21 +
 src/backend/catalog/aclchk.c               |   17 +-
 src/backend/utils/adt/pg_upgrade_support.c |   12 +
 src/bin/initdb/initdb.c                    |    6 +-
 src/bin/pg_dump/dumputils.c                |  274 ++++++-
 src/bin/pg_dump/dumputils.h                |    9 +-
 src/bin/pg_dump/pg_dump.c                  | 1179 ++++++++++++++++++++++------
 src/bin/pg_dump/pg_dump.h                  |   24 +
 src/bin/pg_dump/pg_dumpall.c               |    6 +-
 src/include/catalog/binary_upgrade.h       |    2 +
 src/include/catalog/pg_proc.h              |    2 +
 src/test/regress/expected/init_privs.out   |   13 +
 src/test/regress/parallel_schedule         |    2 +-
 src/test/regress/serial_schedule           |    1 +
 src/test/regress/sql/init_privs.sql        |   11 +
 15 files changed, 1319 insertions(+), 260 deletions(-)
 create mode 100644 src/test/regress/expected/init_privs.out
 create mode 100644 src/test/regress/sql/init_privs.sql

diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index 4a88381..df3b9d9 100644
--- a/doc/src/sgml/extend.sgml
+++ b/doc/src/sgml/extend.sgml
@@ -339,6 +339,27 @@
    </para>
 
    <para>
+    The extension script may set privileges on objects which are part of the
+    extension via <command>GRANT</command> and <command>REVOKE</command>
+    statements.  The final set of privileges for each object (if any are set)
+    will be stored in the
+    <link linkend="catalog-pg-init-privs"><structname>pg_init_privs</structname></link>
+    system catalog.  When <application>pg_dump</> is used, the
+    <command>CREATE EXTENSION</> command will be included in the dump, followed
+    by the set of <command>GRANT</command> and <command>REVOKE</command>
+    statements necessary to set the privileges on the objects to what they were
+    at the time the dump was taken.
+   </para>
+
+   <para>
+    <productname>PostgreSQL</> does not currently support extension scripts
+    issuing <command>CREATE POLICY</command> or <command>SECURITY LABEL</command>
+    statements.  These are expected to be set after the extension has been
+    created.  All RLS policies and security labels on extension objects will be
+    included in dumps created by <application>pg_dump</>.
+   </para>
+
+   <para>
     The extension mechanism also has provisions for packaging modification
     scripts that adjust the definitions of the SQL objects contained in an
     extension.  For example, if version 1.1 of an extension adds one function
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index ffb6678..975fe13 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -22,6 +22,7 @@
 #include "access/htup_details.h"
 #include "access/sysattr.h"
 #include "access/xact.h"
+#include "catalog/binary_upgrade.h"
 #include "catalog/catalog.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
@@ -85,6 +86,12 @@ typedef struct
 	DropBehavior behavior;
 } InternalDefaultACL;
 
+/*
+ * When performing a binary-upgrade, pg_dump will call a function to set
+ * this variable to let us know that we need to populate the pg_init_privs
+ * table for the GRANT/REVOKE commands while this variable is set to true.
+ */
+bool		binary_upgrade_record_init_privs = false;
 
 static void ExecGrantStmt_oids(InternalGrant *istmt);
 static void ExecGrant_Relation(InternalGrant *grantStmt);
@@ -5237,7 +5244,15 @@ recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
 	HeapTuple	tuple;
 	HeapTuple	oldtuple;
 
-	if (!creating_extension)
+	/*
+	 * Generally, we only record the initial privileges when an extension is
+	 * being created, but because we don't actually use CREATE EXTENSION
+	 * during binary upgrades with pg_upgrade, there is a variable to let us
+	 * know that the GRANT and REVOKE statements being issued, while this
+	 * variable is true, are for the initial privileges of the extension
+	 * object and therefore we need to record them.
+	 */
+	if (!creating_extension && !binary_upgrade_record_init_privs)
 		return;
 
 	relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c
index 912eada..6ff035a 100644
--- a/src/backend/utils/adt/pg_upgrade_support.c
+++ b/src/backend/utils/adt/pg_upgrade_support.c
@@ -29,6 +29,7 @@ Datum		binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS);
 Datum		binary_upgrade_set_next_pg_enum_oid(PG_FUNCTION_ARGS);
 Datum		binary_upgrade_set_next_pg_authid_oid(PG_FUNCTION_ARGS);
 Datum		binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS);
+Datum		binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS);
 
 
 #define CHECK_IS_BINARY_UPGRADE									\
@@ -193,3 +194,14 @@ binary_upgrade_create_empty_extension(PG_FUNCTION_ARGS)
 
 	PG_RETURN_VOID();
 }
+
+Datum
+binary_upgrade_set_record_init_privs(PG_FUNCTION_ARGS)
+{
+	bool		record_init_privs = PG_GETARG_BOOL(0);
+
+	CHECK_IS_BINARY_UPGRADE;
+	binary_upgrade_record_init_privs = record_init_privs;
+
+	PG_RETURN_VOID();
+}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 858667b..18a3826 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -2002,7 +2002,11 @@ setup_privileges(FILE *cmdfd)
 	char	  **priv_lines;
 	static char *privileges_setup[] = {
 		"UPDATE pg_class "
-		"  SET relacl = E'{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
+		"  SET relacl = (SELECT array_agg(a.acl) FROM "
+		" (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
+		"  UNION SELECT unnest(pg_catalog.acldefault("
+		"    CASE WHEN relkind = 'S' THEN 's' ELSE 'r' END::\"char\",10::oid))"
+		" ) as a) "
 		"  WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n\n",
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 5301d3f..c55a2fa 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -38,6 +38,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  *		TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
  *		FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
  *	acls: the ACL string fetched from the database
+ *	racls: the ACL string of any initial-but-now-revoked privileges
  *	owner: username of object owner (will be passed through fmtId); can be
  *		NULL or empty string to indicate "no owner known"
  *	prefix: string to prefix to each generated command; typically empty
@@ -54,13 +55,15 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  */
 bool
 buildACLCommands(const char *name, const char *subname,
-				 const char *type, const char *acls, const char *owner,
-				 const char *prefix, int remoteVersion,
+				 const char *type, const char *acls, const char *racls,
+				 const char *owner, const char *prefix, int remoteVersion,
 				 PQExpBuffer sql)
 {
 	bool		ok = true;
-	char	  **aclitems;
-	int			naclitems;
+	char	  **aclitems = NULL;
+	char	  **raclitems = NULL;
+	int			naclitems = 0;
+	int			nraclitems = 0;
 	int			i;
 	PQExpBuffer grantee,
 				grantor,
@@ -70,18 +73,31 @@ buildACLCommands(const char *name, const char *subname,
 				secondsql;
 	bool		found_owner_privs = false;
 
-	if (strlen(acls) == 0)
+	if (strlen(acls) == 0 && strlen(racls) == 0)
 		return true;			/* object has default permissions */
 
 	/* treat empty-string owner same as NULL */
 	if (owner && *owner == '\0')
 		owner = NULL;
 
-	if (!parsePGArray(acls, &aclitems, &naclitems))
+	if (strlen(acls) != 0)
 	{
-		if (aclitems)
-			free(aclitems);
-		return false;
+		if (!parsePGArray(acls, &aclitems, &naclitems))
+		{
+			if (aclitems)
+				free(aclitems);
+			return false;
+		}
+	}
+
+	if (strlen(racls) != 0)
+	{
+		if (!parsePGArray(racls, &raclitems, &nraclitems))
+		{
+			if (raclitems)
+				free(raclitems);
+			return false;
+		}
 	}
 
 	grantee = createPQExpBuffer();
@@ -90,24 +106,101 @@ buildACLCommands(const char *name, const char *subname,
 	privswgo = createPQExpBuffer();
 
 	/*
-	 * At the end, these two will be pasted together to form the result. But
-	 * the owner privileges need to go before the other ones to keep the
-	 * dependencies valid.  In recent versions this is normally the case, but
-	 * in old versions they come after the PUBLIC privileges and that results
-	 * in problems if we need to run REVOKE on the owner privileges.
+	 * At the end, these two will be pasted together to form the result.
+	 *
+	 * For older systems we use these to ensure that the owner privileges go
+	 * before the other ones, as a GRANT could create the default entry for
+	 * the object, which generally includes all rights for the owner. In more
+	 * recent versions we normally handle this because the owner rights come
+	 * first in the ACLs, but older versions might have them after the PUBLIC
+	 * privileges.
+	 *
+	 * For 9.6 and later systems, much of this changes.  With 9.6, we check
+	 * the default privileges for the objects at dump time and create two sets
+	 * of ACLs- "racls" which are the ACLs to REVOKE from the object (as the
+	 * object may have initial privileges on it, along with any default ACLs
+	 * which are not part of the current set of privileges), and regular
+	 * "acls", which are the ACLs to GRANT to the object.  We handle the
+	 * REVOKEs first, followed by the GRANTs.
 	 */
 	firstsql = createPQExpBuffer();
 	secondsql = createPQExpBuffer();
 
 	/*
-	 * Always start with REVOKE ALL FROM PUBLIC, so that we don't have to
-	 * wire-in knowledge about the default public privileges for different
-	 * kinds of objects.
+	 * For pre-9.6 systems, we always start with REVOKE ALL FROM PUBLIC, as we
+	 * don't wish to make any assumptions about what the default ACLs are, and
+	 * we do not collect them during the dump phase (and racls will always be
+	 * the empty set, see above).
+	 *
+	 * For 9.6 and later, if any revoke ACLs have been provided, then include
+	 * them in 'firstsql'.
+	 *
+	 * Revoke ACLs happen when an object starts out life with a set of
+	 * privileges (eg: GRANT SELECT ON pg_class TO PUBLIC;) and the user has
+	 * decided to revoke those rights.  Since those objects come into being
+	 * with those default privileges, we have to revoke them to match what the
+	 * current state of affairs is.  Note that we only started explicitly
+	 * tracking such initial rights in 9.6, and prior to that all initial
+	 * rights are actually handled by the simple 'REVOKE ALL .. FROM PUBLIC'
+	 * case, for initdb-created objects.  Prior to 9.6, we didn't handle
+	 * extensions correctly, but we do now by tracking their initial
+	 * privileges, in the same way we track initdb initial privileges, see
+	 * pg_init_privs.
 	 */
-	appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
-	if (subname)
-		appendPQExpBuffer(firstsql, "(%s)", subname);
-	appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+	if (remoteVersion < 90600)
+	{
+		Assert(nraclitems == 0);
+
+		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
+		if (subname)
+			appendPQExpBuffer(firstsql, "(%s)", subname);
+		appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
+	}
+	else
+	{
+		/* Scan individual REVOKE ACL items */
+		for (i = 0; i < nraclitems; i++)
+		{
+			if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion,
+							  grantee, grantor, privs, privswgo))
+			{
+				ok = false;
+				break;
+			}
+
+			if (privs->len > 0 || privswgo->len > 0)
+			{
+				if (privs->len > 0)
+				{
+					appendPQExpBuffer(firstsql, "%sREVOKE %s ON %s %s FROM ",
+									  prefix, privs->data, type, name);
+					if (grantee->len == 0)
+						appendPQExpBufferStr(firstsql, "PUBLIC;\n");
+					else if (strncmp(grantee->data, "group ",
+									 strlen("group ")) == 0)
+						appendPQExpBuffer(firstsql, "GROUP %s;\n",
+									fmtId(grantee->data + strlen("group ")));
+					else
+						appendPQExpBuffer(firstsql, "%s;\n",
+										  fmtId(grantee->data));
+				}
+				if (privswgo->len > 0)
+				{
+					appendPQExpBuffer(firstsql,
+							   "%sREVOKE GRANT OPTION FOR %s ON %s %s FROM ",
+									  prefix, privswgo->data, type, name);
+					if (grantee->len == 0)
+						appendPQExpBufferStr(firstsql, "PUBLIC");
+					else if (strncmp(grantee->data, "group ",
+									 strlen("group ")) == 0)
+						appendPQExpBuffer(firstsql, "GROUP %s",
+									fmtId(grantee->data + strlen("group ")));
+					else
+						appendPQExpBufferStr(firstsql, fmtId(grantee->data));
+				}
+			}
+		}
+	}
 
 	/*
 	 * We still need some hacking though to cover the case where new default
@@ -138,7 +231,14 @@ buildACLCommands(const char *name, const char *subname,
 
 		if (privs->len > 0 || privswgo->len > 0)
 		{
-			if (owner
+			/*
+			 * Prior to 9.6, we had to handle owner privileges in a special
+			 * manner by first REVOKE'ing the rights and then GRANT'ing them
+			 * after.  With 9.6 and above, what we need to REVOKE and what we
+			 * need to GRANT is figured out when we dump and stashed into
+			 * "racls" and "acls", respectivly.  See above.
+			 */
+			if (remoteVersion < 90600 && owner
 				&& strcmp(grantee->data, owner) == 0
 				&& strcmp(grantor->data, owner) == 0)
 			{
@@ -172,7 +272,14 @@ buildACLCommands(const char *name, const char *subname,
 			else
 			{
 				/*
-				 * Otherwise can assume we are starting from no privs.
+				 * For systems prior to 9.6, we can assume we are starting
+				 * from no privs at this point.
+				 *
+				 * For 9.6 and above, at this point we have issued REVOKE
+				 * statements for all initial and default privileges which are
+				 * no longer present on the object (as they were passed in as
+				 * 'racls') and we can simply GRANT the rights which are in
+				 * 'acls'.
 				 */
 				if (grantor->len > 0
 					&& (!owner || strcmp(owner, grantor->data) != 0))
@@ -215,9 +322,12 @@ buildACLCommands(const char *name, const char *subname,
 	}
 
 	/*
-	 * If we didn't find any owner privs, the owner must have revoked 'em all
+	 * For systems prior to 9.6, if we didn't find any owner privs, the owner
+	 * must have revoked 'em all.
+	 *
+	 * For 9.6 and above, we handle this through the 'racls'.  See above.
 	 */
-	if (!found_owner_privs && owner)
+	if (remoteVersion < 90600 && !found_owner_privs && owner)
 	{
 		appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
 		if (subname)
@@ -235,7 +345,11 @@ buildACLCommands(const char *name, const char *subname,
 	destroyPQExpBuffer(firstsql);
 	destroyPQExpBuffer(secondsql);
 
-	free(aclitems);
+	if (aclitems)
+		free(aclitems);
+
+	if (raclitems)
+		free(raclitems);
 
 	return ok;
 }
@@ -275,7 +389,7 @@ buildDefaultACLCommands(const char *type, const char *nspname,
 		appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
 
 	result = buildACLCommands("", NULL,
-							  type, acls, owner,
+							  type, acls, "", owner,
 							  prefix->data, remoteVersion,
 							  sql);
 
@@ -555,3 +669,109 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
 		appendPQExpBufferStr(buffer, ";\n");
 	}
 }
+
+/*
+ * buildACLQueries
+ *
+ * Build the subqueries to extract out the correct set of ACLs to be
+ * GRANT'd and REVOKE'd for the specific kind of object, accounting for any
+ * initial privileges (from pg_init_privs) and based on if we are in binary
+ * upgrade mode or not.
+ *
+ * Also builds subqueries to extract out the set of ACLs to go from the object
+ * default privileges to the privileges in pg_init_privs, if we are in binary
+ * upgrade mode, so that those privileges can be set up and recorded in the new
+ * cluster before the regular privileges are added on top of those.
+ */
+void
+buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
+				PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery,
+				const char *acl_column, const char *acl_owner,
+				const char *obj_kind, bool binary_upgrade)
+{
+	/*
+	 * To get the delta from what the permissions were at creation time
+	 * (either initdb or CREATE EXTENSION) vs. what they are now, we have to
+	 * look at two things:
+	 *
+	 * What privileges have been added, which we calculate by extracting all
+	 * the current privileges (using the set of default privileges for the
+	 * object type if current privileges are NULL) and then removing those
+	 * which existed at creation time (again, using the set of default
+	 * privileges for the object type if there were no creation time
+	 * privileges).
+	 *
+	 * What privileges have been removed, which we calculate by extracting the
+	 * privileges as they were at creation time (or the default privileges, as
+	 * above), and then removing the current privileges (or the default
+	 * privileges, if current privileges are NULL).
+	 *
+	 * As a good cross-check, both directions of these checks should result in
+	 * the empty set if both the current ACL and the initial privs are NULL
+	 * (meaning, in practice, that the default ACLs were there at init time
+	 * and is what the current privileges are).
+	 *
+	 * We always perform this delta on all ACLs and expect that by the time
+	 * these are run the initial privileges will be in place, even in a
+	 * binary upgrade situation (see below).
+	 */
+	printfPQExpBuffer(acl_subquery, "(SELECT array_agg(acl) FROM "
+					  "(SELECT unnest(coalesce(%s,acldefault(%s,%s))) AS acl "
+					  "EXCEPT "
+		 "SELECT unnest(coalesce(pip.initprivs,acldefault(%s,%s)))) as foo)",
+					  acl_column,
+					  obj_kind,
+					  acl_owner,
+					  obj_kind,
+					  acl_owner);
+
+	printfPQExpBuffer(racl_subquery, "(SELECT array_agg(acl) FROM "
+		  "(SELECT unnest(coalesce(pip.initprivs,acldefault(%s,%s))) AS acl "
+					  "EXCEPT "
+					"SELECT unnest(coalesce(%s,acldefault(%s,%s)))) as foo)",
+					  obj_kind,
+					  acl_owner,
+					  acl_column,
+					  obj_kind,
+					  acl_owner);
+
+	/*
+	 * In binary upgrade mode we don't run the extension script but instead
+	 * dump out the objects independently and then recreate them.  To preserve
+	 * the initial privileges which were set on extension objects, we need to
+	 * grab the set of GRANT and REVOKE commands necessary to get from the
+	 * default privileges of an object to the initial privileges as recorded
+	 * in pg_init_privs.
+	 *
+	 * These will then be run ahead of the regular ACL commands, which were
+	 * calculated using the queries above, inside of a block which sets a flag
+	 * to indicate that the backend should record the results of these GRANT
+	 * and REVOKE statements into pg_init_privs.  This is how we preserve the
+	 * contents of that catalog across binary upgrades.
+	 */
+	if (binary_upgrade)
+	{
+		printfPQExpBuffer(init_acl_subquery,
+						  "CASE WHEN privtype = 'e' THEN "
+						  "(SELECT array_agg(acl) FROM "
+						  "(SELECT unnest(pip.initprivs) AS acl "
+						  "EXCEPT "
+						  "SELECT unnest(acldefault(%s,%s))) as foo) END",
+						  obj_kind,
+						  acl_owner);
+
+		printfPQExpBuffer(init_racl_subquery,
+						  "CASE WHEN privtype = 'e' THEN "
+						  "(SELECT array_agg(acl) FROM "
+						  "(SELECT unnest(acldefault(%s,%s)) AS acl "
+						  "EXCEPT "
+						  "SELECT unnest(pip.initprivs)) as foo) END",
+						  obj_kind,
+						  acl_owner);
+	}
+	else
+	{
+		printfPQExpBuffer(init_acl_subquery, "NULL");
+		printfPQExpBuffer(init_racl_subquery, "NULL");
+	}
+}
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 4b404be..b2fd7d3 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -37,8 +37,8 @@
 
 
 extern bool buildACLCommands(const char *name, const char *subname,
-				 const char *type, const char *acls, const char *owner,
-				 const char *prefix, int remoteVersion,
+				 const char *type, const char *acls, const char *racls,
+				 const char *owner, const char *prefix, int remoteVersion,
 				 PQExpBuffer sql);
 extern bool buildDefaultACLCommands(const char *type, const char *nspname,
 						const char *acls, const char *owner,
@@ -49,4 +49,9 @@ extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name,
 extern void emitShSecLabels(PGconn *conn, PGresult *res,
 				PQExpBuffer buffer, const char *target, const char *objname);
 
+extern void buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
+				PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery,
+				const char *acl_column, const char *acl_owner,
+				const char *obj_kind, bool binary_upgrade);
+
 #endif   /* DUMPUTILS_H */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 650c17a..7e94b0e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -206,7 +206,8 @@ static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 		const char *type, const char *name, const char *subname,
 		const char *tag, const char *nspname, const char *owner,
-		const char *acls);
+		const char *acls, const char *racls,
+		const char *initacls, const char *initracls);
 
 static void getDependencies(Archive *fout);
 static void BuildArchiveDependencies(Archive *fout);
@@ -1268,7 +1269,7 @@ expand_table_name_patterns(Archive *fout,
  * Returns true if object is an extension member, else false.
  */
 static bool
-checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
+checkExtensionMembership(DumpableObject *dobj, Archive *fout)
 {
 	ExtensionInfo *ext = findOwningExtension(dobj->catId);
 
@@ -1281,12 +1282,26 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
 	addObjectDependency(dobj, ext->dobj.dumpId);
 
 	/*
-	 * Normally, mark the member object as not to be dumped.  But in binary
-	 * upgrades, we still dump the members individually, since the idea is to
-	 * exactly reproduce the database contents rather than replace the
-	 * extension contents with something different.
+	 * In 9.6 and above, mark the member object to have any non-initial ACL,
+	 * policies, and security lables dumped.
+	 *
+	 * Note that any initial ACLs (see pg_init_privs) will be removed when we
+	 * extract the information about the object.  We don't provide support for
+	 * initial policies and security labels and it seems unlikely for those to
+	 * ever exist, but we may have to revisit this later.
+	 *
+	 * Prior to 9.6, we do not include any extension member components.
+	 *
+	 * In binary upgrades, we still dump all components of the members
+	 * individually, since the idea is to exactly reproduce the database
+	 * contents rather than replace the extension contents with something
+	 * different.
 	 */
-	if (!dopt->binary_upgrade)
+	if (!fout->dopt->binary_upgrade && fout->remoteVersion >= 90600)
+		dobj->dump = DUMP_COMPONENT_ACL |
+			DUMP_COMPONENT_SECLABEL |
+			DUMP_COMPONENT_POLICY;
+	else if (!fout->dopt->binary_upgrade)
 		dobj->dump = DUMP_COMPONENT_NONE;
 	else
 		dobj->dump = ext->dobj.dump;
@@ -1299,9 +1314,9 @@ checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
  *		Mark a namespace as to be dumped or not
  */
 static void
-selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
+selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
 {
-	if (checkExtensionMembership(&nsinfo->dobj, dopt))
+	if (checkExtensionMembership(&nsinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1316,7 +1331,17 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
 			simple_oid_list_member(&schema_include_oids,
 								   nsinfo->dobj.catId.oid) ?
-							DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+	else if (fout->remoteVersion >= 90600 &&
+			 strncmp(nsinfo->dobj.name, "pg_catalog",
+					 strlen("pg_catalog")) == 0)
+
+		/*
+		 * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
+		 * they are interesting (and not the original ACLs which were set at
+		 * initdb time, see pg_init_privs).
+		 */
+		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
@@ -1337,9 +1362,9 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
  *		Mark a table as to be dumped or not
  */
 static void
-selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
+selectDumpableTable(TableInfo *tbinfo, Archive *fout)
 {
-	if (checkExtensionMembership(&tbinfo->dobj, dopt))
+	if (checkExtensionMembership(&tbinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1349,7 +1374,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
 	if (table_include_oids.head != NULL)
 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
 												   tbinfo->dobj.catId.oid) ?
-								DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 	else
 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
 
@@ -1376,7 +1401,7 @@ selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
  * object (the table or base type).
  */
 static void
-selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
+selectDumpableType(TypeInfo *tyinfo, Archive *fout)
 {
 	/* skip complex types, except for standalone composite types */
 	if (OidIsValid(tyinfo->typrelid) &&
@@ -1405,7 +1430,7 @@ selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
 		 */
 	}
 
-	if (checkExtensionMembership(&tyinfo->dobj, dopt))
+	if (checkExtensionMembership(&tyinfo->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/* Dump based on if the contents of the namespace are being dumped */
@@ -1443,15 +1468,15 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
  * OID is in the range reserved for initdb.
  */
 static void
-selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
+selectDumpableCast(CastInfo *cast, Archive *fout)
 {
-	if (checkExtensionMembership(&cast->dobj, dopt))
+	if (checkExtensionMembership(&cast->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		cast->dobj.dump = dopt->include_everything ?
+		cast->dobj.dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1464,15 +1489,15 @@ selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
  * language's OID is in the range reserved for initdb.
  */
 static void
-selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
+selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
 {
-	if (checkExtensionMembership(&plang->dobj, dopt))
+	if (checkExtensionMembership(&plang->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = dopt->include_everything ?
+		plang->dobj.dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1485,15 +1510,16 @@ selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
  * method's OID is in the range reserved for initdb.
  */
 static void
-selectDumpableAccessMethod(AccessMethodInfo *method, DumpOptions *dopt)
+selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 {
-	if (checkExtensionMembership(&method->dobj, dopt))
+	if (checkExtensionMembership(&method->dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	if (method->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		method->dobj.dump = false;
+		method->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		method->dobj.dump = dopt->include_everything;
+		method->dobj.dump = fout->dopt->include_everything ?
+			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -1523,9 +1549,9 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
  * Use this only for object types without a special-case routine above.
  */
 static void
-selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
+selectDumpableObject(DumpableObject *dobj, Archive *fout)
 {
-	if (checkExtensionMembership(dobj, dopt))
+	if (checkExtensionMembership(dobj, fout))
 		return;					/* extension membership overrides all else */
 
 	/*
@@ -1535,7 +1561,7 @@ selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
 	if (dobj->namespace)
 		dobj->dump = dobj->namespace->dobj.dump_contains;
 	else
-		dobj->dump = dopt->include_everything ?
+		dobj->dump = fout->dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
 }
 
@@ -1978,22 +2004,22 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
 
 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
 		ArchiveEntry(fout,
-					 tdinfo->dobj.catId,	/* catalog ID */
-					 tdinfo->dobj.dumpId,	/* dump ID */
-					 tbinfo->dobj.name,		/* Name */
-					 tbinfo->dobj.namespace->dobj.name,		/* Namespace */
-					 NULL,			/* Tablespace */
-					 tbinfo->rolname,		/* Owner */
-					 false,			/* with oids */
-					 "MATERIALIZED VIEW DATA",		/* Desc */
-					 SECTION_POST_DATA,		/* Section */
-					 q->data,		/* Create */
-					 "",			/* Del */
-					 NULL,			/* Copy */
-					 tdinfo->dobj.dependencies,		/* Deps */
-					 tdinfo->dobj.nDeps,	/* # Deps */
-					 NULL,			/* Dumper */
-					 NULL);			/* Dumper Arg */
+					 tdinfo->dobj.catId,		/* catalog ID */
+					 tdinfo->dobj.dumpId,		/* dump ID */
+					 tbinfo->dobj.name, /* Name */
+					 tbinfo->dobj.namespace->dobj.name, /* Namespace */
+					 NULL,		/* Tablespace */
+					 tbinfo->rolname,	/* Owner */
+					 false,		/* with oids */
+					 "MATERIALIZED VIEW DATA",	/* Desc */
+					 SECTION_POST_DATA, /* Section */
+					 q->data,	/* Create */
+					 "",		/* Del */
+					 NULL,		/* Copy */
+					 tdinfo->dobj.dependencies, /* Deps */
+					 tdinfo->dobj.nDeps,		/* # Deps */
+					 NULL,		/* Dumper */
+					 NULL);		/* Dumper Arg */
 
 	destroyPQExpBuffer(q);
 }
@@ -2729,12 +2755,19 @@ dumpStdStrings(Archive *AH)
 static void
 getBlobs(Archive *fout)
 {
+	DumpOptions *dopt = fout->dopt;
 	PQExpBuffer blobQry = createPQExpBuffer();
 	BlobInfo   *binfo;
 	DumpableObject *bdata;
 	PGresult   *res;
 	int			ntups;
 	int			i;
+	int			i_oid;
+	int			i_lomowner;
+	int			i_lomacl;
+	int			i_rlomacl;
+	int			i_initlomacl;
+	int			i_initrlomacl;
 
 	/* Verbose message */
 	if (g_verbose)
@@ -2744,52 +2777,102 @@ getBlobs(Archive *fout)
 	selectSourceSchema(fout, "pg_catalog");
 
 	/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
-	if (fout->remoteVersion >= 90000)
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer init_acl_subquery = createPQExpBuffer();
+		PQExpBuffer init_racl_subquery = createPQExpBuffer();
+
+		buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
+						init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
+						dopt->binary_upgrade);
+
 		appendPQExpBuffer(blobQry,
-						  "SELECT oid, (%s lomowner) AS rolname, lomacl"
+						  "SELECT l.oid, (%s l.lomowner) AS rolname, "
+						  "%s AS lomacl, "
+						  "%s AS rlomacl, "
+						  "%s AS initlomacl, "
+						  "%s AS initrlomacl "
+						  "FROM pg_largeobject_metadata l "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(l.oid = pip.objoid AND pip.classoid = "
+				"(SELECT oid FROM pg_class WHERE relname = 'pg_largeobject')"
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  init_acl_subquery->data,
+						  init_racl_subquery->data);
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(init_acl_subquery);
+		destroyPQExpBuffer(init_racl_subquery);
+	}
+	else if (fout->remoteVersion >= 90000)
+		appendPQExpBuffer(blobQry,
+						  "SELECT oid, (%s lomowner) AS rolname, lomacl, "
+						  "NULL AS rlomacl, NULL as initlomacl, "
+						  "NULL as initrlomacl "
 						  " FROM pg_largeobject_metadata",
 						  username_subquery);
 	else if (fout->remoteVersion >= 70100)
 		appendPQExpBufferStr(blobQry,
-							 "SELECT DISTINCT loid, NULL::oid, NULL::oid"
+							 "SELECT DISTINCT loid, NULL::oid, NULL, "
+							 "NULL AS rlomacl, NULL AS initlomacl, "
+							 "NULL AS initrlomacl "
 							 " FROM pg_largeobject");
 	else
 		appendPQExpBufferStr(blobQry,
-							 "SELECT oid, NULL::oid, NULL::oid"
+							 "SELECT oid, NULL::oid, NULL, "
+							 "NULL AS rlomacl, NULL AS initlomacl, "
+							 "NULL AS initrlomacl "
 							 " FROM pg_class WHERE relkind = 'l'");
 
 	res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
 
+	i_oid = PQfnumber(res, "oid");
+	i_lomowner = PQfnumber(res, "rolname");
+	i_lomacl = PQfnumber(res, "lomacl");
+	i_rlomacl = PQfnumber(res, "rlomacl");
+	i_initlomacl = PQfnumber(res, "initlomacl");
+	i_initrlomacl = PQfnumber(res, "initrlomacl");
+
 	ntups = PQntuples(res);
-	if (ntups > 0)
+
+	/*
+	 * Each large object has its own BLOB archive entry.
+	 */
+	binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+
+	for (i = 0; i < ntups; i++)
 	{
-		/*
-		 * Each large object has its own BLOB archive entry.
-		 */
-		binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
+		binfo[i].dobj.objType = DO_BLOB;
+		binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
+		binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+		AssignDumpId(&binfo[i].dobj);
 
-		for (i = 0; i < ntups; i++)
-		{
-			binfo[i].dobj.objType = DO_BLOB;
-			binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
-			binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
-			AssignDumpId(&binfo[i].dobj);
-
-			binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
-			if (!PQgetisnull(res, i, 1))
-				binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
-			else
-				binfo[i].rolname = "";
-			if (!PQgetisnull(res, i, 2))
-				binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
-			else
-				binfo[i].blobacl = NULL;
-		}
+		binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
+		binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
+		binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
+		binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
+		binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
+		binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
 
-		/*
-		 * If we have any large objects, a "BLOBS" archive entry is needed.
-		 * This is just a placeholder for sorting; it carries no data now.
-		 */
+		if (PQgetisnull(res, i, i_lomacl) && PQgetisnull(res, i, i_rlomacl) &&
+			PQgetisnull(res, i, i_initlomacl) &&
+			PQgetisnull(res, i, i_initrlomacl))
+			binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
+	}
+
+	/*
+	 * If we have any large objects, a "BLOBS" archive entry is needed. This
+	 * is just a placeholder for sorting; it carries no data now.
+	 */
+	if (ntups > 0)
+	{
 		bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
 		bdata->objType = DO_BLOB_DATA;
 		bdata->catId = nilCatalogId;
@@ -2850,7 +2933,8 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
 		dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 				binfo->dobj.name, NULL, cquery->data,
-				NULL, binfo->rolname, binfo->blobacl);
+				NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
+				binfo->initblobacl, binfo->initrblobacl);
 
 	destroyPQExpBuffer(cquery);
 	destroyPQExpBuffer(dquery);
@@ -3381,6 +3465,9 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	int			i_nspname;
 	int			i_rolname;
 	int			i_nspacl;
+	int			i_rnspacl;
+	int			i_initnspacl;
+	int			i_initrnspacl;
 
 	/*
 	 * Before 7.3, there are no real namespaces; create two dummy entries, one
@@ -3397,8 +3484,11 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[0].dobj.name = pg_strdup("public");
 		nsinfo[0].rolname = pg_strdup("");
 		nsinfo[0].nspacl = pg_strdup("");
+		nsinfo[0].rnspacl = pg_strdup("");
+		nsinfo[0].initnspacl = pg_strdup("");
+		nsinfo[0].initrnspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[0], dopt);
+		selectDumpableNamespace(&nsinfo[0], fout);
 
 		nsinfo[1].dobj.objType = DO_NAMESPACE;
 		nsinfo[1].dobj.catId.tableoid = 0;
@@ -3407,8 +3497,11 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[1].dobj.name = pg_strdup("pg_catalog");
 		nsinfo[1].rolname = pg_strdup("");
 		nsinfo[1].nspacl = pg_strdup("");
+		nsinfo[1].rnspacl = pg_strdup("");
+		nsinfo[1].initnspacl = pg_strdup("");
+		nsinfo[1].initrnspacl = pg_strdup("");
 
-		selectDumpableNamespace(&nsinfo[1], dopt);
+		selectDumpableNamespace(&nsinfo[1], fout);
 
 		*numNamespaces = 2;
 
@@ -3424,10 +3517,46 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	 * we fetch all namespaces including system ones, so that every object we
 	 * read in can be linked to a containing namespace.
 	 */
-	appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
-					  "(%s nspowner) AS rolname, "
-					  "nspacl FROM pg_namespace",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer init_acl_subquery = createPQExpBuffer();
+		PQExpBuffer init_racl_subquery = createPQExpBuffer();
+
+		buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
+						init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
+						dopt->binary_upgrade);
+
+		appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "%s as nspacl, "
+						  "%s as rnspacl, "
+						  "%s as initnspacl, "
+						  "%s as initrnspacl "
+						  "FROM pg_namespace n "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (n.oid = pip.objoid AND pip.classoid = "
+				 "(SELECT oid FROM pg_class WHERE relname = 'pg_namespace') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  init_acl_subquery->data,
+						  init_racl_subquery->data);
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(init_acl_subquery);
+		destroyPQExpBuffer(init_racl_subquery);
+	}
+	else
+		appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
+						  "(%s nspowner) AS rolname, "
+						  "nspacl, NULL as rnspacl, "
+						  "NULL AS initnspacl, NULL as initrnspacl "
+						  "FROM pg_namespace",
+						  username_subquery);
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -3440,6 +3569,9 @@ getNamespaces(Archive *fout, int *numNamespaces)
 	i_nspname = PQfnumber(res, "nspname");
 	i_rolname = PQfnumber(res, "rolname");
 	i_nspacl = PQfnumber(res, "nspacl");
+	i_rnspacl = PQfnumber(res, "rnspacl");
+	i_initnspacl = PQfnumber(res, "initnspacl");
+	i_initrnspacl = PQfnumber(res, "initrnspacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -3450,9 +3582,25 @@ getNamespaces(Archive *fout, int *numNamespaces)
 		nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
 		nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
+		nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
+		nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
+		nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
 
 		/* Decide whether to dump this namespace */
-		selectDumpableNamespace(&nsinfo[i], dopt);
+		selectDumpableNamespace(&nsinfo[i], fout);
+
+		/*
+		 * Do not try to dump ACL if the ACL is empty or the default.
+		 *
+		 * This is useful because, for some schemas/objects, the only
+		 * component we are going to try and dump is the ACL and if we can
+		 * remove that then 'dump' goes to zero/false and we don't consider
+		 * this object for dumping at all later on.
+		 */
+		if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
+			PQgetisnull(res, i, i_initnspacl) &&
+			PQgetisnull(res, i, i_initrnspacl))
+			nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(nsinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
@@ -3612,6 +3760,9 @@ getTypes(Archive *fout, int *numTypes)
 	int			i_typname;
 	int			i_typnamespace;
 	int			i_typacl;
+	int			i_rtypacl;
+	int			i_inittypacl;
+	int			i_initrtypacl;
 	int			i_rolname;
 	int			i_typinput;
 	int			i_typoutput;
@@ -3641,10 +3792,52 @@ getTypes(Archive *fout, int *numTypes)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90200)
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer initacl_subquery = createPQExpBuffer();
+		PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						initracl_subquery, "t.typacl", "t.typowner", "'T'",
+						dopt->binary_upgrade);
+
+		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
+						  "t.typnamespace, "
+						  "%s AS typacl, "
+						  "%s AS rtypacl, "
+						  "%s AS inittypacl, "
+						  "%s AS initrtypacl, "
+						  "(%s t.typowner) AS rolname, "
+						  "t.typinput::oid AS typinput, "
+					 "t.typoutput::oid AS typoutput, t.typelem, t.typrelid, "
+						  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
+						  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
+						  "t.typtype, t.typisdefined, "
+						  "t.typname[0] = '_' AND t.typelem != 0 AND "
+						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
+						  "FROM pg_type t "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (t.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) ",
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  initacl_subquery->data,
+						  initracl_subquery->data,
+						  username_subquery);
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(initacl_subquery);
+		destroyPQExpBuffer(initracl_subquery);
+	}
+	else if (fout->remoteVersion >= 90200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, typacl, "
+						  "typnamespace, typacl, NULL as rtypacl, "
+						  "NULL AS inittypacl, NULL AS initrtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3659,7 +3852,8 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 80300)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, NULL AS typacl, "
+						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
+						  "NULL AS inittypacl, NULL AS initrtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3674,7 +3868,8 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "typnamespace, NULL AS typacl, "
+						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
+						  "NULL AS inittypacl, NULL AS initrtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3688,7 +3883,8 @@ getTypes(Archive *fout, int *numTypes)
 	else if (fout->remoteVersion >= 70100)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-						  "0::oid AS typnamespace, NULL AS typacl, "
+				  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
+						  "NULL AS inittypacl, NULL AS initrtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3704,7 +3900,8 @@ getTypes(Archive *fout, int *numTypes)
 		appendPQExpBuffer(query, "SELECT "
 		 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
 						  "oid, typname, "
-						  "0::oid AS typnamespace, NULL AS typacl, "
+				  "0::oid AS typnamespace, NULL AS typacl, NULL as rtypacl, "
+						  "NULL AS inittypacl, NULL AS initrtypacl, "
 						  "(%s typowner) AS rolname, "
 						  "typinput::oid AS typinput, "
 						  "typoutput::oid AS typoutput, typelem, typrelid, "
@@ -3727,6 +3924,9 @@ getTypes(Archive *fout, int *numTypes)
 	i_typname = PQfnumber(res, "typname");
 	i_typnamespace = PQfnumber(res, "typnamespace");
 	i_typacl = PQfnumber(res, "typacl");
+	i_rtypacl = PQfnumber(res, "rtypacl");
+	i_inittypacl = PQfnumber(res, "inittypacl");
+	i_initrtypacl = PQfnumber(res, "initrtypacl");
 	i_rolname = PQfnumber(res, "rolname");
 	i_typinput = PQfnumber(res, "typinput");
 	i_typoutput = PQfnumber(res, "typoutput");
@@ -3750,6 +3950,9 @@ getTypes(Archive *fout, int *numTypes)
 						  tyinfo[i].dobj.catId.oid);
 		tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
+		tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
+		tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
+		tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
 		tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
 		tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
 		tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
@@ -3767,7 +3970,13 @@ getTypes(Archive *fout, int *numTypes)
 			tyinfo[i].isArray = false;
 
 		/* Decide whether we want to dump it */
-		selectDumpableType(&tyinfo[i], dopt);
+		selectDumpableType(&tyinfo[i], fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
+			PQgetisnull(res, i, i_inittypacl) &&
+			PQgetisnull(res, i, i_initrtypacl))
+			tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		/*
 		 * If it's a domain, fetch info about its constraints, if any
@@ -3875,7 +4084,6 @@ getTypes(Archive *fout, int *numTypes)
 OprInfo *
 getOperators(Archive *fout, int *numOprs)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -3961,7 +4169,7 @@ getOperators(Archive *fout, int *numOprs)
 		oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(oprinfo[i].dobj), dopt);
+		selectDumpableObject(&(oprinfo[i].dobj), fout);
 
 		if (strlen(oprinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
@@ -3985,7 +4193,6 @@ getOperators(Archive *fout, int *numOprs)
 CollInfo *
 getCollations(Archive *fout, int *numCollations)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4047,7 +4254,7 @@ getCollations(Archive *fout, int *numCollations)
 		collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(collinfo[i].dobj), dopt);
+		selectDumpableObject(&(collinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -4067,7 +4274,6 @@ getCollations(Archive *fout, int *numCollations)
 ConvInfo *
 getConversions(Archive *fout, int *numConversions)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4129,7 +4335,7 @@ getConversions(Archive *fout, int *numConversions)
 		convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(convinfo[i].dobj), dopt);
+		selectDumpableObject(&(convinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -4149,7 +4355,6 @@ getConversions(Archive *fout, int *numConversions)
 AccessMethodInfo *
 getAccessMethods(Archive *fout, int *numAccessMethods)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4203,7 +4408,7 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 		aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
 
 		/* Decide whether we want to dump it */
-		selectDumpableAccessMethod(&(aminfo[i]), dopt);
+		selectDumpableAccessMethod(&(aminfo[i]), fout);
 	}
 
 	PQclear(res);
@@ -4224,7 +4429,6 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 OpclassInfo *
 getOpclasses(Archive *fout, int *numOpclasses)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4296,7 +4500,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(opcinfo[i].dobj), dopt);
+		selectDumpableObject(&(opcinfo[i].dobj), fout);
 
 		if (fout->remoteVersion >= 70300)
 		{
@@ -4323,7 +4527,6 @@ getOpclasses(Archive *fout, int *numOpclasses)
 OpfamilyInfo *
 getOpfamilies(Archive *fout, int *numOpfamilies)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -4385,7 +4588,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(opfinfo[i].dobj), dopt);
+		selectDumpableObject(&(opfinfo[i].dobj), fout);
 
 		if (fout->remoteVersion >= 70300)
 		{
@@ -4426,22 +4629,79 @@ getAggregates(Archive *fout, int *numAggs)
 	int			i_proargtypes;
 	int			i_rolname;
 	int			i_aggacl;
+	int			i_raggacl;
+	int			i_initaggacl;
+	int			i_initraggacl;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
 	/*
-	 * Find all user-defined aggregates.  See comment in getFuncs() for the
+	 * Find all interesting aggregates.  See comment in getFuncs() for the
 	 * rationale behind the filtering logic.
 	 */
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer initacl_subquery = createPQExpBuffer();
+		PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						initracl_subquery, "p.proacl", "p.proowner", "'f'",
+						dopt->binary_upgrade);
+
+		appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
+						  "p.proname AS aggname, "
+						  "p.pronamespace AS aggnamespace, "
+						  "p.pronargs, p.proargtypes, "
+						  "(%s p.proowner) AS rolname, "
+						  "%s AS aggacl, "
+						  "%s AS raggacl, "
+						  "%s AS initaggacl, "
+						  "%s AS initraggacl "
+						  "FROM pg_proc p "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(p.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE p.proisagg AND ("
+						  "p.pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  username_subquery,
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  initacl_subquery->data,
+						  initracl_subquery->data);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
 
-	if (fout->remoteVersion >= 80200)
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(initacl_subquery);
+		destroyPQExpBuffer(initracl_subquery);
+	}
+	else if (fout->remoteVersion >= 80200)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
 						  "pronamespace AS aggnamespace, "
 						  "pronargs, proargtypes, "
 						  "(%s proowner) AS rolname, "
-						  "proacl AS aggacl "
+						  "proacl AS aggacl, "
+						  "NULL AS raggacl, "
+						  "NULL AS initaggacl, NULL AS initraggacl "
 						  "FROM pg_proc p "
 						  "WHERE proisagg AND ("
 						  "pronamespace != "
@@ -4464,7 +4724,9 @@ getAggregates(Archive *fout, int *numAggs)
 						  "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
 						  "proargtypes, "
 						  "(%s proowner) AS rolname, "
-						  "proacl AS aggacl "
+						  "proacl AS aggacl, "
+						  "NULL AS raggacl, "
+						  "NULL AS initaggacl, NULL AS initraggacl "
 						  "FROM pg_proc "
 						  "WHERE proisagg "
 						  "AND pronamespace != "
@@ -4478,7 +4740,9 @@ getAggregates(Archive *fout, int *numAggs)
 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 						  "aggbasetype AS proargtypes, "
 						  "(%s aggowner) AS rolname, "
-						  "NULL AS aggacl "
+						  "NULL AS aggacl, "
+						  "NULL AS raggacl, "
+						  "NULL AS initaggacl, NULL AS initraggacl "
 						  "FROM pg_aggregate "
 						  "where oid > '%u'::oid",
 						  username_subquery,
@@ -4493,7 +4757,9 @@ getAggregates(Archive *fout, int *numAggs)
 				  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 						  "aggbasetype AS proargtypes, "
 						  "(%s aggowner) AS rolname, "
-						  "NULL AS aggacl "
+						  "NULL AS aggacl, "
+						  "NULL AS raggacl, "
+						  "NULL AS initaggacl, NULL AS initraggacl "
 						  "FROM pg_aggregate "
 						  "where oid > '%u'::oid",
 						  username_subquery,
@@ -4515,6 +4781,9 @@ getAggregates(Archive *fout, int *numAggs)
 	i_proargtypes = PQfnumber(res, "proargtypes");
 	i_rolname = PQfnumber(res, "rolname");
 	i_aggacl = PQfnumber(res, "aggacl");
+	i_raggacl = PQfnumber(res, "raggacl");
+	i_initaggacl = PQfnumber(res, "initaggacl");
+	i_initraggacl = PQfnumber(res, "initraggacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -4534,6 +4803,9 @@ getAggregates(Archive *fout, int *numAggs)
 		agginfo[i].aggfn.lang = InvalidOid;		/* not currently interesting */
 		agginfo[i].aggfn.prorettype = InvalidOid;		/* not saved */
 		agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
+		agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
+		agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
+		agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
 		agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
 		if (agginfo[i].aggfn.nargs == 0)
 			agginfo[i].aggfn.argtypes = NULL;
@@ -4550,7 +4822,13 @@ getAggregates(Archive *fout, int *numAggs)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(agginfo[i].aggfn.dobj), dopt);
+		selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
+			PQgetisnull(res, i, i_initaggacl) &&
+			PQgetisnull(res, i, i_initraggacl))
+			agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4586,17 +4864,21 @@ getFuncs(Archive *fout, int *numFuncs)
 	int			i_proargtypes;
 	int			i_prorettype;
 	int			i_proacl;
+	int			i_rproacl;
+	int			i_initproacl;
+	int			i_initrproacl;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
 	/*
-	 * Find all user-defined functions.  Normally we can exclude functions in
-	 * pg_catalog, which is worth doing since there are several thousand of
-	 * 'em.  However, there are some extensions that create functions in
-	 * pg_catalog.  In normal dumps we can still ignore those --- but in
-	 * binary-upgrade mode, we must dump the member objects of the extension,
-	 * so be sure to fetch any such functions.
+	 * Find all interesting functions.  We include functions in pg_catalog, if
+	 * they have an ACL different from what we set at initdb time (which is
+	 * saved in pg_init_privs for us to perform this check).  There may also
+	 * be functions which are members of extensions which we must dump if we
+	 * are in binary upgrade mode (we'll mark those functions as to-be-dumped
+	 * when we check if the extension is to-be-dumped and we're in binary
+	 * upgrade mode).
 	 *
 	 * Also, in 9.2 and up, exclude functions that are internally dependent on
 	 * something else, since presumably those will be created as a result of
@@ -4605,12 +4887,69 @@ getFuncs(Archive *fout, int *numFuncs)
 	 * because the constructors don't have any dependencies the range type
 	 * doesn't have; otherwise we might not get creation ordering correct.
 	 */
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer initacl_subquery = createPQExpBuffer();
+		PQExpBuffer initracl_subquery = createPQExpBuffer();
 
-	if (fout->remoteVersion >= 70300)
+		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						initracl_subquery, "p.proacl", "p.proowner", "'f'",
+						dopt->binary_upgrade);
+
+		appendPQExpBuffer(query,
+						  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
+						  "p.pronargs, p.proargtypes, p.prorettype, "
+						  "%s AS proacl, "
+						  "%s AS rproacl, "
+						  "%s AS initproacl, "
+						  "%s AS initrproacl, "
+						  "p.pronamespace, "
+						  "(%s p.proowner) AS rolname "
+						  "FROM pg_proc p "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(p.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE NOT proisagg "
+						  "AND NOT EXISTS (SELECT 1 FROM pg_depend "
+						  "WHERE classid = 'pg_proc'::regclass AND "
+						  "objid = p.oid AND deptype = 'i') AND ("
+						  "pronamespace != "
+						  "(SELECT oid FROM pg_namespace "
+						  "WHERE nspname = 'pg_catalog') OR "
+						  "EXISTS (SELECT * FROM pg_init_privs pip "
+						  "WHERE p.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_proc') "
+						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  initacl_subquery->data,
+						  initracl_subquery->data,
+						  username_subquery);
+		if (dopt->binary_upgrade)
+			appendPQExpBufferStr(query,
+							   "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
+								 "classid = 'pg_proc'::regclass AND "
+								 "objid = p.oid AND "
+								 "refclassid = 'pg_extension'::regclass AND "
+								 "deptype = 'e')");
+		appendPQExpBufferChar(query, ')');
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(initacl_subquery);
+		destroyPQExpBuffer(initracl_subquery);
+	}
+	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query,
 						  "SELECT tableoid, oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, proacl, "
+						  "NULL as rproacl, "
+						  "NULL as initproacl, NULL AS initrproacl, "
 						  "pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc p "
@@ -4639,6 +4978,8 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "SELECT tableoid, oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, "
 						  "NULL AS proacl, "
+						  "NULL AS rproacl, "
+						  "NULL as initproacl, NULL AS initrproacl, "
 						  "0::oid AS pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc "
@@ -4655,6 +4996,8 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "oid, proname, prolang, "
 						  "pronargs, proargtypes, prorettype, "
 						  "NULL AS proacl, "
+						  "NULL AS rproacl, "
+						  "NULL as initproacl, NULL AS initrproacl, "
 						  "0::oid AS pronamespace, "
 						  "(%s proowner) AS rolname "
 						  "FROM pg_proc "
@@ -4681,6 +5024,9 @@ getFuncs(Archive *fout, int *numFuncs)
 	i_proargtypes = PQfnumber(res, "proargtypes");
 	i_prorettype = PQfnumber(res, "prorettype");
 	i_proacl = PQfnumber(res, "proacl");
+	i_rproacl = PQfnumber(res, "rproacl");
+	i_initproacl = PQfnumber(res, "initproacl");
+	i_initrproacl = PQfnumber(res, "initrproacl");
 
 	for (i = 0; i < ntups; i++)
 	{
@@ -4697,6 +5043,9 @@ getFuncs(Archive *fout, int *numFuncs)
 		finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
 		finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
 		finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
+		finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
+		finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
+		finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
 		finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
 		if (finfo[i].nargs == 0)
 			finfo[i].argtypes = NULL;
@@ -4708,7 +5057,13 @@ getFuncs(Archive *fout, int *numFuncs)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(finfo[i].dobj), dopt);
+		selectDumpableObject(&(finfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
+			PQgetisnull(res, i, i_initproacl) &&
+			PQgetisnull(res, i, i_initrproacl))
+			finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(finfo[i].rolname) == 0)
 			write_msg(NULL,
@@ -4725,7 +5080,7 @@ getFuncs(Archive *fout, int *numFuncs)
 
 /*
  * getTables
- *	  read all the user-defined tables (no indexes, no catalogs)
+ *	  read all the tables (no indexes)
  * in the system catalogs return them in the TableInfo* structure
  *
  * numTables is set to the number of tables read in
@@ -4745,6 +5100,9 @@ getTables(Archive *fout, int *numTables)
 	int			i_relnamespace;
 	int			i_relkind;
 	int			i_relacl;
+	int			i_rrelacl;
+	int			i_initrelacl;
+	int			i_initrrelacl;
 	int			i_rolname;
 	int			i_relchecks;
 	int			i_relhastriggers;
@@ -4793,7 +5151,77 @@ getTables(Archive *fout, int *numTables)
 	 * we cannot correctly identify inherited columns, owned sequences, etc.
 	 */
 
-	if (fout->remoteVersion >= 90500)
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer initacl_subquery = createPQExpBuffer();
+		PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+		/*
+		 * Left join to pick up dependency info linking sequences to their
+		 * owning column, if any (note this dependency is AUTO as of 8.2)
+		 *
+		 * Left join to detect if any privileges are still as-set-at-init, in
+		 * which case we won't dump out ACL commands for those.
+		 */
+
+		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						initracl_subquery, "c.relacl", "c.relowner",
+				 "CASE WHEN c.relkind = 'S' THEN 's' ELSE 'r' END::\"char\"",
+						dopt->binary_upgrade);
+
+		appendPQExpBuffer(query,
+						  "SELECT c.tableoid, c.oid, c.relname, "
+						  "%s AS relacl, %s as rrelacl, "
+						  "%s AS initrelacl, %s as initrrelacl, "
+						  "c.relkind, c.relnamespace, "
+						  "(%s c.relowner) AS rolname, "
+						  "c.relchecks, c.relhastriggers, "
+						  "c.relhasindex, c.relhasrules, c.relhasoids, "
+						  "c.relrowsecurity, c.relforcerowsecurity, "
+						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
+						  "tc.relfrozenxid AS tfrozenxid, "
+						  "tc.relminmxid AS tminmxid, "
+						  "c.relpersistence, c.relispopulated, "
+						  "c.relreplident, c.relpages, "
+						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+						  "d.refobjid AS owning_tab, "
+						  "d.refobjsubid AS owning_col, "
+						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
+						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
+						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
+						  "tc.reloptions AS toast_reloptions "
+						  "FROM pg_class c "
+						  "LEFT JOIN pg_depend d ON "
+						  "(c.relkind = '%c' AND "
+						  "d.classid = c.tableoid AND d.objid = c.oid AND "
+						  "d.objsubid = 0 AND "
+						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
+					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(c.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class "
+						  "WHERE relname = 'pg_class') AND pip.objsubid = 0) "
+				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
+						  "ORDER BY c.oid",
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  initacl_subquery->data,
+						  initracl_subquery->data,
+						  username_subquery,
+						  RELKIND_SEQUENCE,
+						  RELKIND_RELATION, RELKIND_SEQUENCE,
+						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(initacl_subquery);
+		destroyPQExpBuffer(initracl_subquery);
+	}
+	else if (fout->remoteVersion >= 90500)
 	{
 		/*
 		 * Left join to pick up dependency info linking sequences to their
@@ -4801,7 +5229,10 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4842,7 +5273,10 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4884,7 +5318,10 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4926,7 +5363,10 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -4966,7 +5406,10 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5005,7 +5448,10 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 						  "c.relchecks, c.relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5044,7 +5490,10 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
-						  "c.relacl, c.relkind, c.relnamespace, "
+						  "c.relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "c.relkind, "
+						  "c.relnamespace, "
 						  "(%s c.relowner) AS rolname, "
 					  "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
@@ -5083,7 +5532,9 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, relname, "
-						  "relacl, relkind, relnamespace, "
+						  "relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "relkind, relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 						  "relhasindex, relhasrules, relhasoids, "
@@ -5121,7 +5572,9 @@ getTables(Archive *fout, int *numTables)
 		 */
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, relname, "
-						  "relacl, relkind, relnamespace, "
+						  "relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "relkind, relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 						  "relhasindex, relhasrules, relhasoids, "
@@ -5154,7 +5607,10 @@ getTables(Archive *fout, int *numTables)
 	else if (fout->remoteVersion >= 70200)
 	{
 		appendPQExpBuffer(query,
-						  "SELECT tableoid, oid, relname, relacl, relkind, "
+						  "SELECT tableoid, oid, relname, relacl, "
+						  "NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "relkind, "
 						  "0::oid AS relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5182,7 +5638,10 @@ getTables(Archive *fout, int *numTables)
 	{
 		/* all tables have oids in 7.1 */
 		appendPQExpBuffer(query,
-						  "SELECT tableoid, oid, relname, relacl, relkind, "
+						  "SELECT tableoid, oid, relname, relacl, "
+						  "NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
+						  "relkind, "
 						  "0::oid AS relnamespace, "
 						  "(%s relowner) AS rolname, "
 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
@@ -5216,7 +5675,8 @@ getTables(Archive *fout, int *numTables)
 		appendPQExpBuffer(query,
 						  "SELECT "
 		"(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
-						  "oid, relname, relacl, "
+						  "oid, relname, relacl, NULL as rrelacl, "
+						  "NULL AS initrelacl, NULL AS initrrelacl, "
 						  "CASE WHEN relhasrules and relkind = 'r' "
 					  "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
 					  "             r.ev_class = c.oid AND r.ev_type = '1') "
@@ -5270,6 +5730,9 @@ getTables(Archive *fout, int *numTables)
 	i_relname = PQfnumber(res, "relname");
 	i_relnamespace = PQfnumber(res, "relnamespace");
 	i_relacl = PQfnumber(res, "relacl");
+	i_rrelacl = PQfnumber(res, "rrelacl");
+	i_initrelacl = PQfnumber(res, "initrelacl");
+	i_initrrelacl = PQfnumber(res, "initrrelacl");
 	i_relkind = PQfnumber(res, "relkind");
 	i_rolname = PQfnumber(res, "rolname");
 	i_relchecks = PQfnumber(res, "relchecks");
@@ -5324,6 +5787,9 @@ getTables(Archive *fout, int *numTables)
 						  tblinfo[i].dobj.catId.oid);
 		tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
+		tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
+		tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
+		tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
 		tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
 		tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
 		tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
@@ -5371,7 +5837,7 @@ getTables(Archive *fout, int *numTables)
 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
 			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
 		else
-			selectDumpableTable(&tblinfo[i], dopt);
+			selectDumpableTable(&tblinfo[i], fout);
 
 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
@@ -6457,7 +6923,6 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 EventTriggerInfo *
 getEventTriggers(Archive *fout, int *numEventTriggers)
 {
-	DumpOptions *dopt = fout->dopt;
 	int			i;
 	PQExpBuffer query;
 	PGresult   *res;
@@ -6527,7 +6992,7 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 		evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(evtinfo[i].dobj), dopt);
+		selectDumpableObject(&(evtinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -6563,17 +7028,59 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	int			i_laninline;
 	int			i_lanvalidator;
 	int			i_lanacl;
+	int			i_rlanacl;
+	int			i_initlanacl;
+	int			i_initrlanacl;
 	int			i_lanowner;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90000)
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer initacl_subquery = createPQExpBuffer();
+		PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
+						dopt->binary_upgrade);
+
+		/* pg_language has a laninline column */
+		appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
+						  "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
+						  "l.laninline, l.lanvalidator, "
+						  "%s AS lanacl, "
+						  "%s AS rlanacl, "
+						  "%s AS initlanacl, "
+						  "%s AS initrlanacl, "
+						  "(%s l.lanowner) AS lanowner "
+						  "FROM pg_language l "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (l.oid = pip.objoid AND pip.classoid = "
+					  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "AND pip.objsubid = 0) "
+						  "WHERE l.lanispl "
+						  "ORDER BY l.oid",
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  initacl_subquery->data,
+						  initracl_subquery->data,
+						  username_subquery);
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(initacl_subquery);
+		destroyPQExpBuffer(initracl_subquery);
+	}
+	else if (fout->remoteVersion >= 90000)
 	{
 		/* pg_language has a laninline column */
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
-						  "laninline, lanvalidator, lanacl, "
+						  "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
+						  "NULL AS initlanacl, NULL AS initrlanacl, "
 						  "(%s lanowner) AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6586,6 +7093,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
+						  "NULL AS initlanacl, NULL AS initrlanacl, "
 						  "(%s lanowner) AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6598,6 +7107,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
+						  "NULL AS initlanacl, NULL AS initrlanacl, "
 						  "(%s '10') AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6610,6 +7121,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
+						  "NULL AS initlanacl, NULL AS initrlanacl, "
 						  "(%s '1') AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6622,6 +7135,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						  "0 AS laninline, lanvalidator, lanacl, "
+						  "NULL AS rlanacl, "
+						  "NULL AS initlanacl, NULL AS initrlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6632,6 +7147,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+						  "NULL AS rlanacl, "
+						  "NULL AS initlanacl, NULL AS initrlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6644,6 +7161,8 @@ getProcLangs(Archive *fout, int *numProcLangs)
 						  "oid, "
 						  "lanname, lanpltrusted, lanplcallfoid, "
 						"0 AS laninline, 0 AS lanvalidator, NULL AS lanacl, "
+						  "NULL AS rlanacl, "
+						  "NULL AS initlanacl, NULL AS initrlanacl, "
 						  "NULL AS lanowner "
 						  "FROM pg_language "
 						  "WHERE lanispl "
@@ -6666,6 +7185,9 @@ getProcLangs(Archive *fout, int *numProcLangs)
 	i_laninline = PQfnumber(res, "laninline");
 	i_lanvalidator = PQfnumber(res, "lanvalidator");
 	i_lanacl = PQfnumber(res, "lanacl");
+	i_rlanacl = PQfnumber(res, "rlanacl");
+	i_initlanacl = PQfnumber(res, "initlanacl");
+	i_initrlanacl = PQfnumber(res, "initrlanacl");
 	i_lanowner = PQfnumber(res, "lanowner");
 
 	for (i = 0; i < ntups; i++)
@@ -6681,10 +7203,19 @@ getProcLangs(Archive *fout, int *numProcLangs)
 		planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
 		planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
 		planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
+		planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
+		planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
+		planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
 		planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
 
 		/* Decide whether we want to dump it */
-		selectDumpableProcLang(&(planginfo[i]), dopt);
+		selectDumpableProcLang(&(planginfo[i]), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
+			PQgetisnull(res, i, i_initlanacl) &&
+			PQgetisnull(res, i, i_initrlanacl))
+			planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (fout->remoteVersion < 70300)
 		{
@@ -6717,7 +7248,6 @@ getProcLangs(Archive *fout, int *numProcLangs)
 CastInfo *
 getCasts(Archive *fout, int *numCasts)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -6823,7 +7353,7 @@ getCasts(Archive *fout, int *numCasts)
 		}
 
 		/* Decide whether we want to dump it */
-		selectDumpableCast(&(castinfo[i]), dopt);
+		selectDumpableCast(&(castinfo[i]), fout);
 	}
 
 	PQclear(res);
@@ -6859,7 +7389,6 @@ get_language_name(Archive *fout, Oid langid)
 TransformInfo *
 getTransforms(Archive *fout, int *numTransforms)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -6934,7 +7463,7 @@ getTransforms(Archive *fout, int *numTransforms)
 		free(lanname);
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(transforminfo[i].dobj), dopt);
+		selectDumpableObject(&(transforminfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7545,7 +8074,6 @@ shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
 TSParserInfo *
 getTSParsers(Archive *fout, int *numTSParsers)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7618,7 +8146,7 @@ getTSParsers(Archive *fout, int *numTSParsers)
 		prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(prsinfo[i].dobj), dopt);
+		selectDumpableObject(&(prsinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7638,7 +8166,6 @@ getTSParsers(Archive *fout, int *numTSParsers)
 TSDictInfo *
 getTSDictionaries(Archive *fout, int *numTSDicts)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7704,7 +8231,7 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 			dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(dictinfo[i].dobj), dopt);
+		selectDumpableObject(&(dictinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7724,7 +8251,6 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 TSTemplateInfo *
 getTSTemplates(Archive *fout, int *numTSTemplates)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7782,7 +8308,7 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 		tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(tmplinfo[i].dobj), dopt);
+		selectDumpableObject(&(tmplinfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7802,7 +8328,6 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 TSConfigInfo *
 getTSConfigurations(Archive *fout, int *numTSConfigs)
 {
-	DumpOptions *dopt = fout->dopt;
 	PGresult   *res;
 	int			ntups;
 	int			i;
@@ -7861,7 +8386,7 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 		cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(cfginfo[i].dobj), dopt);
+		selectDumpableObject(&(cfginfo[i].dobj), fout);
 	}
 
 	PQclear(res);
@@ -7894,6 +8419,9 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	int			i_fdwhandler;
 	int			i_fdwvalidator;
 	int			i_fdwacl;
+	int			i_rfdwacl;
+	int			i_initfdwacl;
+	int			i_initrfdwacl;
 	int			i_fdwoptions;
 
 	/* Before 8.4, there are no foreign-data wrappers */
@@ -7908,12 +8436,55 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	if (fout->remoteVersion >= 90100)
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer initacl_subquery = createPQExpBuffer();
+		PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
+						dopt->binary_upgrade);
+
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
+						  "(%s f.fdwowner) AS rolname, "
+						  "f.fdwhandler::pg_catalog.regproc, "
+						  "f.fdwvalidator::pg_catalog.regproc, "
+						  "%s AS fdwacl, "
+						  "%s AS rfdwacl, "
+						  "%s AS initfdwacl, "
+						  "%s AS initrfdwacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.fdwoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS fdwoptions "
+						  "FROM pg_foreign_data_wrapper f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_data_wrapper') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  initacl_subquery->data,
+						  initracl_subquery->data);
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(initacl_subquery);
+		destroyPQExpBuffer(initracl_subquery);
+	}
+	else if (fout->remoteVersion >= 90100)
 	{
 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
 						  "(%s fdwowner) AS rolname, "
 						  "fdwhandler::pg_catalog.regproc, "
 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
+						  "NULL as rfdwacl, "
+						  "NULL as initfdwacl, NULL AS initrfdwacl, "
 						  "array_to_string(ARRAY("
 						  "SELECT quote_ident(option_name) || ' ' || "
 						  "quote_literal(option_value) "
@@ -7929,6 +8500,8 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 						  "(%s fdwowner) AS rolname, "
 						  "'-' AS fdwhandler, "
 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
+						  "NULL as rfdwacl, "
+						  "NULL as initfdwacl, NULL AS initrfdwacl, "
 						  "array_to_string(ARRAY("
 						  "SELECT quote_ident(option_name) || ' ' || "
 						  "quote_literal(option_value) "
@@ -7953,6 +8526,9 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 	i_fdwhandler = PQfnumber(res, "fdwhandler");
 	i_fdwvalidator = PQfnumber(res, "fdwvalidator");
 	i_fdwacl = PQfnumber(res, "fdwacl");
+	i_rfdwacl = PQfnumber(res, "rfdwacl");
+	i_initfdwacl = PQfnumber(res, "initfdwacl");
+	i_initrfdwacl = PQfnumber(res, "initrfdwacl");
 	i_fdwoptions = PQfnumber(res, "fdwoptions");
 
 	for (i = 0; i < ntups; i++)
@@ -7968,9 +8544,18 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 		fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
 		fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
 		fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
+		fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
+		fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
+		fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(fdwinfo[i].dobj), dopt);
+		selectDumpableObject(&(fdwinfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
+			PQgetisnull(res, i, i_initfdwacl) &&
+			PQgetisnull(res, i, i_initrfdwacl))
+			fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8004,6 +8589,9 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	int			i_srvtype;
 	int			i_srvversion;
 	int			i_srvacl;
+	int			i_rsrvacl;
+	int			i_initsrvacl;
+	int			i_initrsrvacl;
 	int			i_srvoptions;
 
 	/* Before 8.4, there are no foreign servers */
@@ -8018,17 +8606,62 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
 
-	appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
-					  "(%s srvowner) AS rolname, "
-					  "srvfdw, srvtype, srvversion, srvacl,"
-					  "array_to_string(ARRAY("
-					  "SELECT quote_ident(option_name) || ' ' || "
-					  "quote_literal(option_value) "
-					  "FROM pg_options_to_table(srvoptions) "
-					  "ORDER BY option_name"
-					  "), E',\n    ') AS srvoptions "
-					  "FROM pg_foreign_server",
-					  username_subquery);
+	if (fout->remoteVersion >= 90600)
+	{
+		PQExpBuffer acl_subquery = createPQExpBuffer();
+		PQExpBuffer racl_subquery = createPQExpBuffer();
+		PQExpBuffer initacl_subquery = createPQExpBuffer();
+		PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
+						dopt->binary_upgrade);
+
+		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
+						  "(%s f.srvowner) AS rolname, "
+						  "f.srvfdw, f.srvtype, f.srvversion, "
+						  "%s AS srvacl, "
+						  "%s AS rsrvacl, "
+						  "%s AS initsrvacl, "
+						  "%s AS initrsrvacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(f.srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions "
+						  "FROM pg_foreign_server f "
+						  "LEFT JOIN pg_init_privs pip "
+						  "ON (f.oid = pip.objoid AND pip.classoid = "
+			"(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_server') "
+						  "AND pip.objsubid = 0) ",
+						  username_subquery,
+						  acl_subquery->data,
+						  racl_subquery->data,
+						  initacl_subquery->data,
+						  initracl_subquery->data);
+
+		destroyPQExpBuffer(acl_subquery);
+		destroyPQExpBuffer(racl_subquery);
+		destroyPQExpBuffer(initacl_subquery);
+		destroyPQExpBuffer(initracl_subquery);
+	}
+	else
+	{
+		appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
+						  "(%s srvowner) AS rolname, "
+						  "srvfdw, srvtype, srvversion, srvacl, "
+						  "NULL AS rsrvacl, "
+						  "NULL AS initsrvacl, NULL AS initrsrvacl, "
+						  "array_to_string(ARRAY("
+						  "SELECT quote_ident(option_name) || ' ' || "
+						  "quote_literal(option_value) "
+						  "FROM pg_options_to_table(srvoptions) "
+						  "ORDER BY option_name"
+						  "), E',\n    ') AS srvoptions "
+						  "FROM pg_foreign_server",
+						  username_subquery);
+	}
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -8045,6 +8678,9 @@ getForeignServers(Archive *fout, int *numForeignServers)
 	i_srvtype = PQfnumber(res, "srvtype");
 	i_srvversion = PQfnumber(res, "srvversion");
 	i_srvacl = PQfnumber(res, "srvacl");
+	i_rsrvacl = PQfnumber(res, "rsrvacl");
+	i_initsrvacl = PQfnumber(res, "initsrvacl");
+	i_initrsrvacl = PQfnumber(res, "initrsrvacl");
 	i_srvoptions = PQfnumber(res, "srvoptions");
 
 	for (i = 0; i < ntups; i++)
@@ -8061,9 +8697,18 @@ getForeignServers(Archive *fout, int *numForeignServers)
 		srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
 		srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
 		srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
+		srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
+		srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
+		srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
 
 		/* Decide whether we want to dump it */
-		selectDumpableObject(&(srvinfo[i].dobj), dopt);
+		selectDumpableObject(&(srvinfo[i].dobj), fout);
+
+		/* Do not try to dump ACL if no ACL exists. */
+		if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
+			PQgetisnull(res, i, i_initsrvacl) &&
+			PQgetisnull(res, i, i_initrsrvacl))
+			srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8688,7 +9333,8 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
 				qnspname, NULL, nspinfo->dobj.name, NULL,
-				nspinfo->rolname, nspinfo->nspacl);
+				nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
+				nspinfo->initnspacl, nspinfo->initrnspacl);
 
 	free(qnspname);
 
@@ -8983,7 +9629,8 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+				tyinfo->inittypacl, tyinfo->initrtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9121,7 +9768,8 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+				tyinfo->inittypacl, tyinfo->initrtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9196,7 +9844,8 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+				tyinfo->inittypacl, tyinfo->initrtypacl);
 
 	destroyPQExpBuffer(q);
 	destroyPQExpBuffer(delq);
@@ -9590,7 +10239,8 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+				tyinfo->inittypacl, tyinfo->initrtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -9758,7 +10408,8 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+				tyinfo->inittypacl, tyinfo->initrtypacl);
 
 	/* Dump any per-constraint comments */
 	for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -9993,7 +10644,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 		dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
 				qtypname, NULL, tyinfo->dobj.name,
 				tyinfo->dobj.namespace->dobj.name,
-				tyinfo->rolname, tyinfo->typacl);
+				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
+				tyinfo->inittypacl, tyinfo->initrtypacl);
 
 	PQclear(res);
 	destroyPQExpBuffer(q);
@@ -10311,7 +10963,8 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 				qlanname, NULL, plang->dobj.name,
 				lanschema,
-				plang->lanowner, plang->lanacl);
+				plang->lanowner, plang->lanacl, plang->rlanacl,
+				plang->initlanacl, plang->initrlanacl);
 
 	free(qlanname);
 
@@ -10982,7 +11635,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
 				funcsig, NULL, funcsig_tag,
 				finfo->dobj.namespace->dobj.name,
-				finfo->rolname, finfo->proacl);
+				finfo->rolname, finfo->proacl, finfo->rproacl,
+				finfo->initproacl, finfo->initrproacl);
 
 	PQclear(res);
 
@@ -12700,29 +13354,29 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	if (fout->remoteVersion >= 90600)
 	{
 		appendPQExpBuffer(query, "SELECT aggtransfn, "
-			"aggfinalfn, aggtranstype::pg_catalog.regtype, "
-			"aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
-			"aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
-			"aggfinalextra, aggmfinalextra, "
-			"aggsortop::pg_catalog.regoperator, "
-			"aggserialtype::pg_catalog.regtype, "
-			"(aggkind = 'h') AS hypothetical, "
-			"aggtransspace, agginitval, "
-			"aggmtransspace, aggminitval, "
-			"true AS convertok, "
-			"pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
-			"pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
-			"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
-			"WHERE a.aggfnoid = p.oid "
-			"AND p.oid = '%u'::pg_catalog.oid",
-			agginfo->aggfn.dobj.catId.oid);
+						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
+					"aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
+		   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
+						  "aggfinalextra, aggmfinalextra, "
+						  "aggsortop::pg_catalog.regoperator, "
+						  "aggserialtype::pg_catalog.regtype, "
+						  "(aggkind = 'h') AS hypothetical, "
+						  "aggtransspace, agginitval, "
+						  "aggmtransspace, aggminitval, "
+						  "true AS convertok, "
+				  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
+		 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
+					  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
+						  "WHERE a.aggfnoid = p.oid "
+						  "AND p.oid = '%u'::pg_catalog.oid",
+						  agginfo->aggfn.dobj.catId.oid);
 	}
 	else if (fout->remoteVersion >= 90400)
 	{
 		appendPQExpBuffer(query, "SELECT aggtransfn, "
 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
-						  "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
+						"'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
 						  "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
 						  "aggfinalextra, aggmfinalextra, "
 						  "aggsortop::pg_catalog.regoperator, "
@@ -12956,7 +13610,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 
 	if (strcmp(aggcombinefn, "-") != 0)
 	{
-		appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s",	aggcombinefn);
+		appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
 	}
 
 	/*
@@ -12965,9 +13619,9 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 	 */
 	if (strcmp(aggserialfn, "-") != 0)
 	{
-		appendPQExpBuffer(details, ",\n    SERIALFUNC = %s",	aggserialfn);
-		appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s",	aggdeserialfn);
-		appendPQExpBuffer(details, ",\n    SERIALTYPE = %s",	aggserialtype);
+		appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
+		appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
+		appendPQExpBuffer(details, ",\n    SERIALTYPE = %s", aggserialtype);
 	}
 
 	if (strcmp(aggmtransfn, "-") != 0)
@@ -13047,7 +13701,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 		dumpSecLabel(fout, labelq->data,
 					 agginfo->aggfn.dobj.namespace->dobj.name,
 					 agginfo->aggfn.rolname,
-					 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+				   agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
 	/*
 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
@@ -13065,7 +13719,9 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 				"FUNCTION",
 				aggsig, NULL, aggsig_tag,
 				agginfo->aggfn.dobj.namespace->dobj.name,
-				agginfo->aggfn.rolname, agginfo->aggfn.proacl);
+				agginfo->aggfn.rolname, agginfo->aggfn.proacl,
+				agginfo->aggfn.rproacl,
+				agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
 
 	free(aggsig);
 	if (aggfullsig)
@@ -13509,7 +14165,8 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 				"FOREIGN DATA WRAPPER",
 				qfdwname, NULL, fdwinfo->dobj.name,
 				NULL, fdwinfo->rolname,
-				fdwinfo->fdwacl);
+				fdwinfo->fdwacl, fdwinfo->rfdwacl,
+				fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
 
 	/* Dump Foreign Data Wrapper Comments */
 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13605,7 +14262,8 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 				"FOREIGN SERVER",
 				qsrvname, NULL, srvinfo->dobj.name,
 				NULL, srvinfo->rolname,
-				srvinfo->srvacl);
+				srvinfo->srvacl, srvinfo->rsrvacl,
+				srvinfo->initsrvacl, srvinfo->initrsrvacl);
 
 	/* Dump user mappings */
 	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
@@ -13784,7 +14442,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
 		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
 					 tag->data,
-	   daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
+		daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
 					 NULL,
 					 daclinfo->defaclrole,
 					 false, "DEFAULT ACL", SECTION_POST_DATA,
@@ -13811,13 +14469,16 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
  * 'owner' is the owner, NULL if there is no owner (for languages).
  * 'acls' is the string read out of the fooacl system catalog field;
  *		it will be parsed here.
+ * 'racls' contains any initial ACLs that the object had which have now been
+ *		revoked by the user, it will also be parsed here.
  *----------
  */
 static void
 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 		const char *type, const char *name, const char *subname,
 		const char *tag, const char *nspname, const char *owner,
-		const char *acls)
+		const char *acls, const char *racls,
+		const char *initacls, const char *initracls)
 {
 	DumpOptions *dopt = fout->dopt;
 	PQExpBuffer sql;
@@ -13832,11 +14493,30 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 
 	sql = createPQExpBuffer();
 
-	if (!buildACLCommands(name, subname, type, acls, owner,
+	/*
+	 * Check to see if this object has had any initial ACLs included for it.
+	 * If so, we are in binary upgrade mode and these are the ACLs to turn
+	 * into GRANT and REVOKE statements to set and record the initial
+	 * privileges for an extension object.  Let the backend know that these
+	 * are to be recorded by calling binary_upgrade_set_record_init_privs()
+	 * before and after.
+	 */
+	if (strlen(initacls) != 0 || strlen(initracls) != 0)
+	{
+		appendPQExpBuffer(sql, "SELECT binary_upgrade_set_record_init_privs(true);\n");
+		if (!buildACLCommands(name, subname, type, initacls, initracls, owner,
+							  "", fout->remoteVersion, sql))
+			exit_horribly(NULL,
+						  "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
+						  initacls, initracls, name, type);
+		appendPQExpBuffer(sql, "SELECT binary_upgrade_set_record_init_privs(false);\n");
+	}
+
+	if (!buildACLCommands(name, subname, type, acls, racls, owner,
 						  "", fout->remoteVersion, sql))
 		exit_horribly(NULL,
-					"could not parse ACL list (%s) for object \"%s\" (%s)\n",
-					  acls, name, type);
+					  "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
+					  acls, racls, name, type);
 
 	if (sql->len > 0)
 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
@@ -14159,7 +14839,8 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
 static void
 dumpTable(Archive *fout, TableInfo *tbinfo)
 {
-	char		   *namecopy;
+	DumpOptions *dopt = fout->dopt;
+	char	   *namecopy;
 
 	if (tbinfo->relkind == RELKIND_SEQUENCE)
 		dumpSequence(fout, tbinfo);
@@ -14174,12 +14855,13 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 				"TABLE",
 				namecopy, NULL, tbinfo->dobj.name,
 				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-				tbinfo->relacl);
+				tbinfo->relacl, tbinfo->rrelacl,
+				tbinfo->initrelacl, tbinfo->initrrelacl);
 
 	/*
-	 * Handle column ACLs, if any.  Note: we pull these with a separate
-	 * query rather than trying to fetch them during getTableAttrs, so
-	 * that we won't miss ACLs on system columns.
+	 * Handle column ACLs, if any.  Note: we pull these with a separate query
+	 * rather than trying to fetch them during getTableAttrs, so that we won't
+	 * miss ACLs on system columns.
 	 */
 	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
 	{
@@ -14187,18 +14869,65 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 		PGresult   *res;
 		int			i;
 
-		appendPQExpBuffer(query,
-				   "SELECT attname, attacl FROM pg_catalog.pg_attribute "
-						  "WHERE attrelid = '%u' AND NOT attisdropped "
-						  "AND attacl IS NOT NULL "
-						  "ORDER BY attnum",
-						  tbinfo->dobj.catId.oid);
+		if (fout->remoteVersion >= 90600)
+		{
+			PQExpBuffer acl_subquery = createPQExpBuffer();
+			PQExpBuffer racl_subquery = createPQExpBuffer();
+			PQExpBuffer initacl_subquery = createPQExpBuffer();
+			PQExpBuffer initracl_subquery = createPQExpBuffer();
+
+			buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
+						 initracl_subquery, "at.attacl", "c.relowner", "'c'",
+							dopt->binary_upgrade);
+
+			appendPQExpBuffer(query,
+							  "SELECT at.attname, "
+							  "%s AS attacl, "
+							  "%s AS rattacl, "
+							  "%s AS initattacl, "
+							  "%s AS initrattacl "
+							  "FROM pg_catalog.pg_attribute at "
+					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+							  "LEFT JOIN pg_init_privs pip ON "
+							  "(pip.classoid = "
+				 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
+				   " at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
+							  "WHERE at.attrelid = '%u' AND "
+							  "NOT at.attisdropped "
+							  "AND at.attacl IS NOT NULL "
+							  "ORDER BY at.attnum",
+							  acl_subquery->data,
+							  racl_subquery->data,
+							  initacl_subquery->data,
+							  initracl_subquery->data,
+							  tbinfo->dobj.catId.oid);
+
+			destroyPQExpBuffer(acl_subquery);
+			destroyPQExpBuffer(racl_subquery);
+			destroyPQExpBuffer(initacl_subquery);
+			destroyPQExpBuffer(initracl_subquery);
+		}
+		else
+		{
+			appendPQExpBuffer(query,
+							  "SELECT attname, attacl, NULL as rattacl, "
+							  "NULL AS initattacl, NULL AS initrattacl "
+							  "FROM pg_catalog.pg_attribute "
+							  "WHERE attrelid = '%u' AND NOT attisdropped "
+							  "AND attacl IS NOT NULL "
+							  "ORDER BY attnum",
+							  tbinfo->dobj.catId.oid);
+		}
+
 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
 		for (i = 0; i < PQntuples(res); i++)
 		{
 			char	   *attname = PQgetvalue(res, i, 0);
 			char	   *attacl = PQgetvalue(res, i, 1);
+			char	   *rattacl = PQgetvalue(res, i, 2);
+			char	   *initattacl = PQgetvalue(res, i, 3);
+			char	   *initrattacl = PQgetvalue(res, i, 4);
 			char	   *attnamecopy;
 			char	   *acltag;
 
@@ -14208,7 +14937,7 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 			dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
 					namecopy, attnamecopy, acltag,
 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-					attacl);
+					attacl, rattacl, initattacl, initrattacl);
 			free(attnamecopy);
 			free(acltag);
 		}
@@ -14905,7 +15634,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			   (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
 					 reltypename,
 					 tbinfo->postponed_def ?
-						SECTION_POST_DATA : SECTION_PRE_DATA,
+					 SECTION_POST_DATA : SECTION_PRE_DATA,
 					 q->data, delq->data, NULL,
 					 NULL, 0,
 					 NULL, NULL);
@@ -15889,15 +16618,15 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 					  fmtId(tbinfo->dobj.name));
 
 	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
-			ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
-						 tginfo->dobj.name,
-						 tbinfo->dobj.namespace->dobj.name,
-						 NULL,
-						 tbinfo->rolname, false,
-						 "TRIGGER", SECTION_POST_DATA,
-						 query->data, delqry->data, NULL,
-						 NULL, 0,
-						 NULL, NULL);
+		ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
+					 tginfo->dobj.name,
+					 tbinfo->dobj.namespace->dobj.name,
+					 NULL,
+					 tbinfo->rolname, false,
+					 "TRIGGER", SECTION_POST_DATA,
+					 query->data, delqry->data, NULL,
+					 NULL, 0,
+					 NULL, NULL);
 
 	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
 		dumpComment(fout, labelq->data,
@@ -16284,7 +17013,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 				TableInfo  *configtbl;
 				Oid			configtbloid = atooid(extconfigarray[j]);
 				bool		dumpobj =
-								curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
+				curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
 
 				configtbl = findTableByOid(configtbloid);
 				if (configtbl == NULL)
@@ -16304,7 +17033,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 
 					/* check table's schema explicitly requested */
 					if (configtbl->dobj.namespace->dobj.dump &
-							DUMP_COMPONENT_DATA)
+						DUMP_COMPONENT_DATA)
 						dumpobj = true;
 				}
 
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 85f9f48..7314cbe 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -113,6 +113,9 @@ typedef struct _namespaceInfo
 	DumpableObject dobj;
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *nspacl;
+	char	   *rnspacl;
+	char	   *initnspacl;
+	char	   *initrnspacl;
 } NamespaceInfo;
 
 typedef struct _extensionInfo
@@ -135,6 +138,9 @@ typedef struct _typeInfo
 	 */
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *typacl;
+	char	   *rtypacl;
+	char	   *inittypacl;
+	char	   *initrtypacl;
 	Oid			typelem;
 	Oid			typrelid;
 	char		typrelkind;		/* 'r', 'v', 'c', etc */
@@ -164,6 +170,9 @@ typedef struct _funcInfo
 	Oid		   *argtypes;
 	Oid			prorettype;
 	char	   *proacl;
+	char	   *rproacl;
+	char	   *initproacl;
+	char	   *initrproacl;
 } FuncInfo;
 
 /* AggInfo is a superset of FuncInfo */
@@ -220,6 +229,9 @@ typedef struct _tableInfo
 	DumpableObject dobj;
 	char	   *rolname;		/* name of owner, or empty string */
 	char	   *relacl;
+	char	   *rrelacl;
+	char	   *initrelacl;
+	char	   *initrrelacl;
 	char		relkind;
 	char		relpersistence; /* relation persistence */
 	bool		relispopulated; /* relation is populated */
@@ -388,6 +400,9 @@ typedef struct _procLangInfo
 	Oid			laninline;
 	Oid			lanvalidator;
 	char	   *lanacl;
+	char	   *rlanacl;
+	char	   *initlanacl;
+	char	   *initrlanacl;
 	char	   *lanowner;		/* name of owner, or empty string */
 } ProcLangInfo;
 
@@ -457,6 +472,9 @@ typedef struct _fdwInfo
 	char	   *fdwvalidator;
 	char	   *fdwoptions;
 	char	   *fdwacl;
+	char	   *rfdwacl;
+	char	   *initfdwacl;
+	char	   *initrfdwacl;
 } FdwInfo;
 
 typedef struct _foreignServerInfo
@@ -467,6 +485,9 @@ typedef struct _foreignServerInfo
 	char	   *srvtype;
 	char	   *srvversion;
 	char	   *srvacl;
+	char	   *rsrvacl;
+	char	   *initsrvacl;
+	char	   *initrsrvacl;
 	char	   *srvoptions;
 } ForeignServerInfo;
 
@@ -483,6 +504,9 @@ typedef struct _blobInfo
 	DumpableObject dobj;
 	char	   *rolname;
 	char	   *blobacl;
+	char	   *rblobacl;
+	char	   *initblobacl;
+	char	   *initrblobacl;
 } BlobInfo;
 
 /*
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 530d3f4..a594937 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1113,8 +1113,8 @@ dumpTablespaces(PGconn *conn)
 							  fspcname, spcoptions);
 
 		if (!skip_acls &&
-			!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner,
-							  "", server_version, buf))
+			!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, "",
+							  spcowner, "", server_version, buf))
 		{
 			fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
 					progname, spcacl, fspcname);
@@ -1444,7 +1444,7 @@ dumpCreateDB(PGconn *conn)
 		}
 
 		if (!skip_acls &&
-			!buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner,
+			!buildACLCommands(fdbname, NULL, "DATABASE", dbacl, "", dbowner,
 							  "", server_version, buf))
 		{
 			fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h
index e7da413..709373c 100644
--- a/src/include/catalog/binary_upgrade.h
+++ b/src/include/catalog/binary_upgrade.h
@@ -30,4 +30,6 @@ extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_class_oid;
 extern PGDLLIMPORT Oid binary_upgrade_next_pg_enum_oid;
 extern PGDLLIMPORT Oid binary_upgrade_next_pg_authid_oid;
 
+extern PGDLLIMPORT bool binary_upgrade_record_init_privs;
+
 #endif   /* BINARY_UPGRADE_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index a0edf93..bf2c05b 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -5239,6 +5239,8 @@ DATA(insert OID = 3590 ( binary_upgrade_set_next_pg_authid_oid PGNSP PGUID	12 1
 DESCR("for use by pg_upgrade");
 DATA(insert OID = 3591 ( binary_upgrade_create_empty_extension PGNSP PGUID	12 1 0 0 0 f f f f f f v r 7 0 2278 "25 25 16 25 1028 1009 1009" _null_ _null_ _null_ _null_ _null_ binary_upgrade_create_empty_extension _null_ _null_ _null_ ));
 DESCR("for use by pg_upgrade");
+DATA(insert OID = 3577 ( binary_upgrade_set_record_init_privs PGNSP PGUID	12 1 0 0 0 f f f f t f v r 1 0 2278 "16" _null_ _null_ _null_ _null_ _null_ binary_upgrade_set_record_init_privs _null_ _null_ _null_ ));
+DESCR("for use by pg_upgrade");
 
 /* replication/origin.h */
 DATA(insert OID = 6003 ( pg_replication_origin_create PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 26 "25" _null_ _null_ _null_ _null_ _null_ pg_replication_origin_create _null_ _null_ _null_ ));
diff --git a/src/test/regress/expected/init_privs.out b/src/test/regress/expected/init_privs.out
new file mode 100644
index 0000000..980940f
--- /dev/null
+++ b/src/test/regress/expected/init_privs.out
@@ -0,0 +1,13 @@
+-- Test iniital privileges
+-- There should always be some initial privileges, set up by initdb
+SELECT count(*) > 0 FROM pg_init_privs;
+ ?column? 
+----------
+ t
+(1 row)
+
+CREATE ROLE init_privs_test_role1;
+CREATE ROLE init_privs_test_role2;
+-- Intentionally include some non-initial privs for pg_dump to dump out
+GRANT SELECT ON pg_proc TO init_privs_test_role1;
+GRANT SELECT (prosrc) ON pg_proc TO init_privs_test_role2;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 7c7b58d..6c1f21b 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -84,7 +84,7 @@ test: select_into select_distinct select_distinct_on select_implicit select_havi
 # ----------
 # Another group of parallel tests
 # ----------
-test: brin gin gist spgist privileges security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator
+test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator
 
 # ----------
 # Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 1b66516..8269c52 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -105,6 +105,7 @@ test: gin
 test: gist
 test: spgist
 test: privileges
+test: init_privs
 test: security_label
 test: collate
 test: matview
diff --git a/src/test/regress/sql/init_privs.sql b/src/test/regress/sql/init_privs.sql
new file mode 100644
index 0000000..38d4a88
--- /dev/null
+++ b/src/test/regress/sql/init_privs.sql
@@ -0,0 +1,11 @@
+-- Test iniital privileges
+
+-- There should always be some initial privileges, set up by initdb
+SELECT count(*) > 0 FROM pg_init_privs;
+
+CREATE ROLE init_privs_test_role1;
+CREATE ROLE init_privs_test_role2;
+
+-- Intentionally include some non-initial privs for pg_dump to dump out
+GRANT SELECT ON pg_proc TO init_privs_test_role1;
+GRANT SELECT (prosrc) ON pg_proc TO init_privs_test_role2;
-- 
2.5.0


From 3c10f0ca8c4e8c1044c746d6154215de54037302 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 14 Mar 2016 11:05:25 -0400
Subject: [PATCH 5/5] Use GRANT system to manage access to sensitive functions

Now that pg_dump will properly dump out any ACL changes made to
functions which exist in pg_catalog, switch to using the GRANT system
to manage access to those functions.

This means removing 'if (!superuser()) ereport()' checks from the
functions themselves and then REVOKEing EXECUTE right from 'public' for
these functions in system_views.sql.
---
 doc/src/sgml/backup.sgml               |  8 +++--
 doc/src/sgml/func.sgml                 | 19 ++++++------
 doc/src/sgml/monitoring.sgml           | 12 +++++---
 src/backend/access/transam/xlogfuncs.c | 56 +++++++++++++---------------------
 src/backend/catalog/system_views.sql   | 21 +++++++++++++
 src/backend/postmaster/pgstat.c        | 24 ++++++---------
 src/backend/utils/adt/misc.c           | 16 ++++------
 7 files changed, 81 insertions(+), 75 deletions(-)

diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 9092cf8..8c65df2 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -826,7 +826,9 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 &amp;&amp; cp pg_xlog/
    </listitem>
    <listitem>
     <para>
-     Connect to the database as a superuser and issue the command:
+     Connect to the database as a user with rights to run pg_start_backup
+     (superuser, or a user who has been granted EXECUTE on the function)
+     and issue the command:
 <programlisting>
 SELECT pg_start_backup('label');
 </programlisting>
@@ -877,7 +879,9 @@ SELECT pg_start_backup('label', true);
    </listitem>
    <listitem>
     <para>
-     Again connect to the database as a superuser, and issue the command:
+     Again connect to the database as a user with rights to run
+     pg_stop_backup (superuser, or a user who has been granted EXECUTE on
+     the function), and issue the command:
 <programlisting>
 SELECT pg_stop_backup();
 </programlisting>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index c6017e6..acba5b4 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17302,8 +17302,9 @@ SELECT set_config('log_statement_stats', 'off', false);
    <para>
     The functions shown in <xref
     linkend="functions-admin-signal-table"> send control signals to
-    other server processes.  Use of these functions is usually restricted
-    to superusers, with noted exceptions.
+    other server processes.  Use of these functions is restricted to
+    superusers by default but access may be granted to others with the
+    <command>GRANT</command>, with noted exceptions.
    </para>
 
    <table id="functions-admin-signal-table">
@@ -17453,7 +17454,7 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_create_restore_point(<parameter>name</> <type>text</>)</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Create a named point for performing restore (restricted to superusers)</entry>
+       <entry>Create a named point for performing restore (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
@@ -17481,21 +17482,21 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> <optional>, <parameter>exclusive</> <type>boolean</> </optional></optional>)</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Prepare for performing on-line backup (restricted to superusers or replication roles)</entry>
+       <entry>Prepare for performing on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_stop_backup()</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Finish performing exclusive on-line backup (restricted to superusers or replication roles)</entry>
+       <entry>Finish performing exclusive on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
         <literal><function>pg_stop_backup(<parameter>exclusive</> <type>boolean</>)</function></literal>
         </entry>
        <entry><type>setof record</type></entry>
-       <entry>Finish performing exclusive or non-exclusive on-line backup (restricted to superusers or replication roles)</entry>
+       <entry>Finish performing exclusive or non-exclusive on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
@@ -17516,7 +17517,7 @@ SELECT set_config('log_statement_stats', 'off', false);
         <literal><function>pg_switch_xlog()</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
-       <entry>Force switch to a new transaction log file (restricted to superusers)</entry>
+       <entry>Force switch to a new transaction log file (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
@@ -17784,7 +17785,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
         <literal><function>pg_xlog_replay_pause()</function></literal>
         </entry>
        <entry><type>void</type></entry>
-       <entry>Pauses recovery immediately (restricted to superusers).
+       <entry>Pauses recovery immediately (restricted to superusers by default, but other users can be granted EXECUTE to run the function).
        </entry>
       </row>
       <row>
@@ -17792,7 +17793,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
         <literal><function>pg_xlog_replay_resume()</function></literal>
         </entry>
        <entry><type>void</type></entry>
-       <entry>Restarts recovery if it was paused (restricted to superusers).
+       <entry>Restarts recovery if it was paused (restricted to superusers by default, but other users can be granted EXECUTE to run the function).
        </entry>
       </row>
      </tbody>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 105d541..5ab3acc 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2289,7 +2289,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset all statistics counters for the current database to zero
-       (requires superuser privileges)
+       (requires superuser privileges by default, but EXECUTE for this
+       function can be granted to others.)
       </entry>
      </row>
 
@@ -2298,7 +2299,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset some cluster-wide statistics counters to zero, depending on the
-       argument (requires superuser privileges).
+       argument (requires superuser privileges by default, but EXECUTE for
+       this functiion can be granted to others).
        Calling <literal>pg_stat_reset_shared('bgwriter')</> will zero all the
        counters shown in the <structname>pg_stat_bgwriter</> view.
        Calling <literal>pg_stat_reset_shared('archiver')</> will zero all the
@@ -2311,7 +2313,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset statistics for a single table or index in the current database to
-       zero (requires superuser privileges)
+       zero (requires superuser privileges by default, but EXECUTE for this
+       function can be granted to others)
       </entry>
      </row>
 
@@ -2320,7 +2323,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <entry><type>void</type></entry>
       <entry>
        Reset statistics for a single function in the current database to
-       zero (requires superuser privileges)
+       zero (requires superuser privileges by default, but EXECUTE for this
+       function can be granted to others)
       </entry>
      </row>
     </tbody>
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 6a2fffc..d69a924 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -66,6 +66,9 @@ nonexclusive_base_backup_cleanup(int code, Datum arg)
  * contains the user-supplied label string (typically this would be used
  * to tell where the backup dump will be stored) and the starting time and
  * starting WAL location for the dump.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_start_backup(PG_FUNCTION_ARGS)
@@ -79,11 +82,6 @@ pg_start_backup(PG_FUNCTION_ARGS)
 
 	backupidstr = text_to_cstring(backupid);
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		   errmsg("must be superuser or replication role to run a backup")));
-
 	if (exclusive_backup_running || nonexclusive_backup_running)
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -142,17 +140,15 @@ pg_start_backup(PG_FUNCTION_ARGS)
  * Note: this version is only called to stop an exclusive backup. The function
  *       pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
  *       stop non-exclusive backups.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_stop_backup(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	stoppoint;
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-		 (errmsg("must be superuser or replication role to run a backup"))));
-
 	if (nonexclusive_backup_running)
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -179,6 +175,9 @@ pg_stop_backup(PG_FUNCTION_ARGS)
  * Works the same as pg_stop_backup, except for non-exclusive backups it returns
  * the backup label and tablespace map files as text fields in as part of the
  * resultset.
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_stop_backup_v2(PG_FUNCTION_ARGS)
@@ -205,11 +204,6 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
 				 errmsg("materialize mode required, but it is not " \
 						"allowed in this context")));
 
-	if (!superuser() && !has_rolreplication(GetUserId()))
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser or replication role to run a backup"))));
-
 	/* Build a tuple descriptor for our result type */
 	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
 		elog(ERROR, "return type must be a row type");
@@ -285,17 +279,15 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
 
 /*
  * pg_switch_xlog: switch to next xlog file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_switch_xlog(PG_FUNCTION_ARGS)
 {
 	XLogRecPtr	switchpoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-			 (errmsg("must be superuser to switch transaction log files"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -312,6 +304,9 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
 
 /*
  * pg_create_restore_point: a named point for restore
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_create_restore_point(PG_FUNCTION_ARGS)
@@ -320,11 +315,6 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
 	char	   *restore_name_str;
 	XLogRecPtr	restorepoint;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to create a restore point"))));
-
 	if (RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -546,15 +536,13 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_pause - pause recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -568,15 +556,13 @@ pg_xlog_replay_pause(PG_FUNCTION_ARGS)
 
 /*
  * pg_xlog_replay_resume - resume recovery now
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_xlog_replay_resume(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to control recovery"))));
-
 	if (!RecoveryInProgress())
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2bd40a1..25b9511 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -997,3 +997,24 @@ RETURNS text[]
 LANGUAGE INTERNAL
 STRICT IMMUTABLE
 AS 'parse_ident';
+
+-- The default permissions for functions mean that anyone can execute them.
+-- A number of functions shouldn't be executable by just anyone, but rather
+-- than use explicit 'superuser()' checks in those functions, we use the GRANT
+-- system to REVOKE access to those functions at initdb time.  Administrators
+-- can later change who can access these functions, or leave them as only
+-- available to superuser / cluster owner, if they choose.
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_switch_xlog() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_pause() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_xlog_replay_resume() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_rotate_logfile() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_reload_conf() FROM public;
+
+REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_table_counters(oid) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM public;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 1467355..41f4374 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -1217,6 +1217,9 @@ pgstat_drop_relation(Oid relid)
  * pgstat_reset_counters() -
  *
  *	Tell the statistics collector to reset counters for our database.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1227,11 +1230,6 @@ pgstat_reset_counters(void)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETCOUNTER);
 	msg.m_databaseid = MyDatabaseId;
 	pgstat_send(&msg, sizeof(msg));
@@ -1241,6 +1239,9 @@ pgstat_reset_counters(void)
  * pgstat_reset_shared_counters() -
  *
  *	Tell the statistics collector to reset cluster-wide shared counters.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1251,11 +1252,6 @@ pgstat_reset_shared_counters(const char *target)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	if (strcmp(target, "archiver") == 0)
 		msg.m_resettarget = RESET_ARCHIVER;
 	else if (strcmp(target, "bgwriter") == 0)
@@ -1274,6 +1270,9 @@ pgstat_reset_shared_counters(const char *target)
  * pgstat_reset_single_counter() -
  *
  *	Tell the statistics collector to reset a single counter.
+ *
+ *	Permission checking for this function is managed through the normal
+ *	GRANT system.
  * ----------
  */
 void
@@ -1284,11 +1283,6 @@ pgstat_reset_single_counter(Oid objoid, PgStat_Single_Reset_Type type)
 	if (pgStatSock == PGINVALID_SOCKET)
 		return;
 
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to reset statistics counters")));
-
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSINGLECOUNTER);
 	msg.m_databaseid = MyDatabaseId;
 	msg.m_resettype = type;
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 6f7c407..ebc7bb3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -321,15 +321,13 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
 
 /*
  * Signal to reload the database configuration
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_reload_conf(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to signal the postmaster"))));
-
 	if (kill(PostmasterPid, SIGHUP))
 	{
 		ereport(WARNING,
@@ -343,15 +341,13 @@ pg_reload_conf(PG_FUNCTION_ARGS)
 
 /*
  * Rotate log file
+ *
+ * Permission checking for this function is managed through the normal
+ * GRANT system.
  */
 Datum
 pg_rotate_logfile(PG_FUNCTION_ARGS)
 {
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 (errmsg("must be superuser to rotate log files"))));
-
 	if (!Logging_collector)
 	{
 		ereport(WARNING,
-- 
2.5.0

#9Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#8)
1 attachment(s)

On Tue, Apr 05, 2016 at 05:50:18PM -0400, Stephen Frost wrote:

I'll be doing more testing, review and clean-up (there are some
whitespace only changes in the later patches that really should be
included in the earlier patches where the code was actually changed)
tonight with plans to push this tomorrow night.

(1) I ran into trouble reconciling the scope of dumpable ACLs. The commit
message indicated this scope:

Subject: [PATCH 4/5] In pg_dump, include pg_catalog and extension ACLs, if
changed

Now that all of the infrastructure exists, add in the ability to
dump out the ACLs of the objects inside of pg_catalog or the ACLs
for objects which are members of extensions, but only if they have
been changed from their original values.

I wrote the attached test script to verify which types of ACLs dump/reload
covers. Based on the commit message, I expected these results:

Dumped: type, class, attribute, proc, largeobject_metadata,
foreign_data_wrapper, foreign_server,
language(in-extension), namespace(in-extension)
Not dumped: database, tablespace,
language(from-initdb), namespace(from-initdb)

Did I interpret the commit message correctly? The script gave these results:

Dumped: type, class, attribute, namespace(from-initdb)
Not dumped: database, tablespace, proc, language(from-initdb)
Not tested: largeobject_metadata, foreign_data_wrapper, foreign_server,
language(in-extension), namespace(in-extension)

I didn't dig into why that happened; the choice of object type may not even be
the root cause in each case. Which of those results, if any, surprise you?

(2) pg_dump queries:

@@ -14187,18 +14869,65 @@ dumpTable(Archive *fout, TableInfo *tbinfo)

+							  "FROM pg_catalog.pg_attribute at "
+					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+							  "LEFT JOIN pg_init_privs pip ON "

Since pg_attribute and pg_class require schema qualification here, so does
pg_init_privs. Likewise elsewhere in the patch's pg_dump changes.

(3) pg_dumpall became much slower around the time of these commits. On one
machine (POWER7 3.55 GHz), a pg_dumpall just after initdb slowed from 0.25s at
commit 6c268df^ to 4.0s at commit 7a54270. On a slower machine (Opteron
1210), pg_dumpall now takes 19s against such a fresh cluster.

I doubt I'll review this patch, but those things have come to my attention.

Attachments:

sysprivs.sqltext/plain; charset=us-asciiDownload
#10Noah Misch
noah@leadboat.com
In reply to: Noah Misch (#9)

On Sun, Apr 17, 2016 at 11:02:28PM -0400, Noah Misch wrote:

On Tue, Apr 05, 2016 at 05:50:18PM -0400, Stephen Frost wrote:

I'll be doing more testing, review and clean-up (there are some
whitespace only changes in the later patches that really should be
included in the earlier patches where the code was actually changed)
tonight with plans to push this tomorrow night.

(2) pg_dump queries:

@@ -14187,18 +14869,65 @@ dumpTable(Archive *fout, TableInfo *tbinfo)

+							  "FROM pg_catalog.pg_attribute at "
+					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+							  "LEFT JOIN pg_init_privs pip ON "

Since pg_attribute and pg_class require schema qualification here, so does
pg_init_privs. Likewise elsewhere in the patch's pg_dump changes.

(3) pg_dumpall became much slower around the time of these commits. On one
machine (POWER7 3.55 GHz), a pg_dumpall just after initdb slowed from 0.25s at
commit 6c268df^ to 4.0s at commit 7a54270. On a slower machine (Opteron
1210), pg_dumpall now takes 19s against such a fresh cluster.

[This is a generic notification.]

The above-described topic is currently a PostgreSQL 9.6 open item. Stephen,
since you committed the patch believed to have created it, you own this open
item. If that responsibility lies elsewhere, please let us know whose
responsibility it is to fix this. Since new open items may be discovered at
any time and I want to plan to have them all fixed well in advance of the ship
date, I will appreciate your efforts toward speedy resolution. Please
present, within 72 hours, a plan to fix the defect within seven days of this
message. Thanks.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#10)

Noah, all,

* Noah Misch (noah@leadboat.com) wrote:

On Sun, Apr 17, 2016 at 11:02:28PM -0400, Noah Misch wrote:

On Tue, Apr 05, 2016 at 05:50:18PM -0400, Stephen Frost wrote:

I'll be doing more testing, review and clean-up (there are some
whitespace only changes in the later patches that really should be
included in the earlier patches where the code was actually changed)
tonight with plans to push this tomorrow night.

(2) pg_dump queries:

@@ -14187,18 +14869,65 @@ dumpTable(Archive *fout, TableInfo *tbinfo)

+							  "FROM pg_catalog.pg_attribute at "
+					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+							  "LEFT JOIN pg_init_privs pip ON "

Since pg_attribute and pg_class require schema qualification here, so does
pg_init_privs. Likewise elsewhere in the patch's pg_dump changes.

(3) pg_dumpall became much slower around the time of these commits. On one
machine (POWER7 3.55 GHz), a pg_dumpall just after initdb slowed from 0.25s at
commit 6c268df^ to 4.0s at commit 7a54270. On a slower machine (Opteron
1210), pg_dumpall now takes 19s against such a fresh cluster.

[This is a generic notification.]

The above-described topic is currently a PostgreSQL 9.6 open item. Stephen,
since you committed the patch believed to have created it, you own this open
item. If that responsibility lies elsewhere, please let us know whose
responsibility it is to fix this. Since new open items may be discovered at
any time and I want to plan to have them all fixed well in advance of the ship
date, I will appreciate your efforts toward speedy resolution. Please
present, within 72 hours, a plan to fix the defect within seven days of this
message. Thanks.

I'm at PGConf.US but will be reviewing this in detail after. The schema
qualification will be easily taken care of, the additional time for
pg_dump is due to the queries looking at the catalog objects and is
therefore relatively fixed and is primairly only a large amount of the
time when dumping databases which are mostly empty.

Thanks!

Stephen

#12Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#11)

On Wed, Apr 20, 2016 at 11:12:44AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Sun, Apr 17, 2016 at 11:02:28PM -0400, Noah Misch wrote:

(3) pg_dumpall became much slower around the time of these commits. On one
machine (POWER7 3.55 GHz), a pg_dumpall just after initdb slowed from 0.25s at
commit 6c268df^ to 4.0s at commit 7a54270. On a slower machine (Opteron
1210), pg_dumpall now takes 19s against such a fresh cluster.

[This is a generic notification.]

The above-described topic is currently a PostgreSQL 9.6 open item. Stephen,
since you committed the patch believed to have created it, you own this open
item. If that responsibility lies elsewhere, please let us know whose
responsibility it is to fix this. Since new open items may be discovered at
any time and I want to plan to have them all fixed well in advance of the ship
date, I will appreciate your efforts toward speedy resolution. Please
present, within 72 hours, a plan to fix the defect within seven days of this
message. Thanks.

I'm at PGConf.US but will be reviewing this in detail after. The schema
qualification will be easily taken care of, the additional time for
pg_dump is due to the queries looking at the catalog objects and is
therefore relatively fixed and is primairly only a large amount of the
time when dumping databases which are mostly empty.

Do you think it would be okay to release 9.6 with pg_dump still adding that
amount of time per database?

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#12)

Noah,

On Wednesday, April 20, 2016, Noah Misch <noah@leadboat.com> wrote:

On Wed, Apr 20, 2016 at 11:12:44AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com <javascript:;>) wrote:

On Sun, Apr 17, 2016 at 11:02:28PM -0400, Noah Misch wrote:

(3) pg_dumpall became much slower around the time of these commits.

On one

machine (POWER7 3.55 GHz), a pg_dumpall just after initdb slowed

from 0.25s at

commit 6c268df^ to 4.0s at commit 7a54270. On a slower machine

(Opteron

1210), pg_dumpall now takes 19s against such a fresh cluster.

[This is a generic notification.]

The above-described topic is currently a PostgreSQL 9.6 open item.

Stephen,

since you committed the patch believed to have created it, you own

this open

item. If that responsibility lies elsewhere, please let us know whose
responsibility it is to fix this. Since new open items may be

discovered at

any time and I want to plan to have them all fixed well in advance of

the ship

date, I will appreciate your efforts toward speedy resolution. Please
present, within 72 hours, a plan to fix the defect within seven days

of this

message. Thanks.

I'm at PGConf.US but will be reviewing this in detail after. The schema
qualification will be easily taken care of, the additional time for
pg_dump is due to the queries looking at the catalog objects and is
therefore relatively fixed and is primairly only a large amount of the
time when dumping databases which are mostly empty.

Do you think it would be okay to release 9.6 with pg_dump still adding that
amount of time per database?

For my 2c, the answer is "yes". I've actually looked at how this could be
improved using a bit of caching in pg_dump for certain things, but I didn't
think those would be appropriate to include in this patch and would be a
general pg_dump performance improvement.

I'm certainly open to improving these issues now if we agree that they
should be fixed for 9.6. If we don't want to include such changes in 9.6
then I will propose then for post-9.6.

Thanks!

Stephen

#14Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#13)

On Wed, Apr 20, 2016 at 10:50:21PM -0400, Stephen Frost wrote:

On Wednesday, April 20, 2016, Noah Misch <noah@leadboat.com> wrote:

On Wed, Apr 20, 2016 at 11:12:44AM -0400, Stephen Frost wrote:

On Sun, Apr 17, 2016 at 11:02:28PM -0400, Noah Misch wrote:

(3) pg_dumpall became much slower around the time of these commits. On one
machine (POWER7 3.55 GHz), a pg_dumpall just after initdb slowed from 0.25s at
commit 6c268df^ to 4.0s at commit 7a54270. On a slower machine (Opteron
1210), pg_dumpall now takes 19s against such a fresh cluster.

the additional time for
pg_dump is due to the queries looking at the catalog objects and is
therefore relatively fixed and is primairly only a large amount of the
time when dumping databases which are mostly empty.

Do you think it would be okay to release 9.6 with pg_dump still adding that
amount of time per database?

For my 2c, the answer is "yes". I've actually looked at how this could be
improved using a bit of caching in pg_dump for certain things, but I didn't
think those would be appropriate to include in this patch and would be a
general pg_dump performance improvement.

I'm certainly open to improving these issues now if we agree that they
should be fixed for 9.6. If we don't want to include such changes in 9.6
then I will propose then for post-9.6.

Folks run clusters with ~1000 databases; we previously accepted at least one
complex performance improvement[1]/messages/by-id/1718942738eb65c8407fcd864883f4c8@fuzzy.cz based on that use case. On the faster of
the two machines I tested, the present thread's commits slowed "pg_dumpall
--schema-only --binary-upgrade" by 1-2s per database. That doubles pg_dump
runtime against the installcheck regression database. A run against a cluster
of one hundred empty databases slowed fifteen-fold, from 8.6s to 131s.
"pg_upgrade -j50" probably will keep things tolerable for the 1000-database
case, but the performance regression remains jarring. I think we should not
release 9.6 with pg_dump performance as it stands today.

[1]: /messages/by-id/1718942738eb65c8407fcd864883f4c8@fuzzy.cz

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Peter Geoghegan
pg@heroku.com
In reply to: Noah Misch (#14)

On Fri, Apr 22, 2016 at 12:25 AM, Noah Misch <noah@leadboat.com> wrote:

Folks run clusters with ~1000 databases; we previously accepted at least one
complex performance improvement[1] based on that use case. On the faster of
the two machines I tested, the present thread's commits slowed "pg_dumpall
--schema-only --binary-upgrade" by 1-2s per database. That doubles pg_dump
runtime against the installcheck regression database. A run against a cluster
of one hundred empty databases slowed fifteen-fold, from 8.6s to 131s.
"pg_upgrade -j50" probably will keep things tolerable for the 1000-database
case, but the performance regression remains jarring. I think we should not
release 9.6 with pg_dump performance as it stands today.

As someone that is responsible for many such clusters, I strongly agree.

--
Peter Geoghegan

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#14)

* Noah Misch (noah@leadboat.com) wrote:

On Wed, Apr 20, 2016 at 10:50:21PM -0400, Stephen Frost wrote:

I'm certainly open to improving these issues now if we agree that they
should be fixed for 9.6. If we don't want to include such changes in 9.6
then I will propose then for post-9.6.

Folks run clusters with ~1000 databases; we previously accepted at least one
complex performance improvement[1] based on that use case. On the faster of
the two machines I tested, the present thread's commits slowed "pg_dumpall
--schema-only --binary-upgrade" by 1-2s per database. That doubles pg_dump
runtime against the installcheck regression database. A run against a cluster
of one hundred empty databases slowed fifteen-fold, from 8.6s to 131s.
"pg_upgrade -j50" probably will keep things tolerable for the 1000-database
case, but the performance regression remains jarring. I think we should not
release 9.6 with pg_dump performance as it stands today.

After looking through the code a bit, I realized that there are a lot of
object types which don't have ACLs at all but which exist in pg_catalog
and were being analyzed because the bitmask for pg_catalog included ACLs
and therefore was non-zero.

Clearing that bit for object types which don't have ACLs improved the
performance for empty databases quite a bit (from about 3s to a bit
under 1s on my laptop). That's a 42-line patch, with comment lines
being half of that, which I'll push once I've looked into the other
concerns which were brought up on this thread.

Much of the remaining inefficiancy is how we query for column
information one table at a time (that appears to be around 300ms of the
900ms or so total time). I'm certainly interested in improving that but
that would require adding more complex data structures to pg_dump than
what we use currently (we'd want to grab all of the columns we care
about in an entire schema and store it locally and then provide a way to
look up that information, etc), so I'm not sure it'd be appropriate to
do now.

I'll look into it again once I've addressed the rest of the issues and
add the TAP-based tests which I've also been working on to actually get
direct testing of pg_dump in the regression suite.

Thanks!

Stephen

#17Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#9)

Noah, all,

* Noah Misch (noah@leadboat.com) wrote:

On Tue, Apr 05, 2016 at 05:50:18PM -0400, Stephen Frost wrote:

Subject: [PATCH 4/5] In pg_dump, include pg_catalog and extension ACLs, if
changed

Now that all of the infrastructure exists, add in the ability to
dump out the ACLs of the objects inside of pg_catalog or the ACLs
for objects which are members of extensions, but only if they have
been changed from their original values.

I wrote the attached test script to verify which types of ACLs dump/reload
covers. Based on the commit message, I expected these results:

Dumped: type, class, attribute, proc, largeobject_metadata,
foreign_data_wrapper, foreign_server,
language(in-extension), namespace(in-extension)
Not dumped: database, tablespace,
language(from-initdb), namespace(from-initdb)

Did I interpret the commit message correctly? The script gave these results:

Dumped: type, class, attribute, namespace(from-initdb)
Not dumped: database, tablespace, proc, language(from-initdb)

You interpreted the commit message correctly and in a number of cases
the correct results are generated, but there's an issue in the WHERE
clause being used for some of the object types. The earlier versions of
this patch adjusted the WHERE clause by using a sub-select, but later I
turned it into a LEFT JOIN and didn't correctly update the WHERE clause
to reflect that, so some kinds of ACL changes weren't being picked up.

That's relatively straight-forward to fix, but I'm going to put
together a series of TAP tests to go with these fixes. While I tested
various options and bits and pieces of the code while developing, this
really needs a proper test suite that runs through all of these
permutations with each change.

I'm planning to have that done by the end of the weekend.

Thanks!

Stephen

#18Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#16)

On Fri, Apr 22, 2016 at 12:31:41PM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Wed, Apr 20, 2016 at 10:50:21PM -0400, Stephen Frost wrote:

I'm certainly open to improving these issues now if we agree that they
should be fixed for 9.6. If we don't want to include such changes in 9.6
then I will propose then for post-9.6.

Folks run clusters with ~1000 databases; we previously accepted at least one
complex performance improvement[1] based on that use case. On the faster of
the two machines I tested, the present thread's commits slowed "pg_dumpall
--schema-only --binary-upgrade" by 1-2s per database. That doubles pg_dump
runtime against the installcheck regression database. A run against a cluster
of one hundred empty databases slowed fifteen-fold, from 8.6s to 131s.
"pg_upgrade -j50" probably will keep things tolerable for the 1000-database
case, but the performance regression remains jarring. I think we should not
release 9.6 with pg_dump performance as it stands today.

After looking through the code a bit, I realized that there are a lot of
object types which don't have ACLs at all but which exist in pg_catalog
and were being analyzed because the bitmask for pg_catalog included ACLs
and therefore was non-zero.

Clearing that bit for object types which don't have ACLs improved the
performance for empty databases quite a bit (from about 3s to a bit
under 1s on my laptop). That's a 42-line patch, with comment lines
being half of that, which I'll push once I've looked into the other
concerns which were brought up on this thread.

That's good news.

Much of the remaining inefficiancy is how we query for column
information one table at a time (that appears to be around 300ms of the
900ms or so total time). I'm certainly interested in improving that but
that would require adding more complex data structures to pg_dump than
what we use currently (we'd want to grab all of the columns we care
about in an entire schema and store it locally and then provide a way to
look up that information, etc), so I'm not sure it'd be appropriate to
do now.

I'm not sure, either; I'd need to see more to decide. If I were you, I would
draft a patch to the point where the community can see the complexity and the
performance change. That should be enough to inform the choice among moving
forward with the proposed complexity, soliciting other designs, reverting the
original changes, or accepting for 9.6 the slowdown as it stands at that time.
Other people may have more definite opinions already.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#17)

On Fri, Apr 22, 2016 at 08:24:53PM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Tue, Apr 05, 2016 at 05:50:18PM -0400, Stephen Frost wrote:

Subject: [PATCH 4/5] In pg_dump, include pg_catalog and extension ACLs, if
changed

Now that all of the infrastructure exists, add in the ability to
dump out the ACLs of the objects inside of pg_catalog or the ACLs
for objects which are members of extensions, but only if they have
been changed from their original values.

I wrote the attached test script to verify which types of ACLs dump/reload
covers. Based on the commit message, I expected these results:

Dumped: type, class, attribute, proc, largeobject_metadata,
foreign_data_wrapper, foreign_server,
language(in-extension), namespace(in-extension)
Not dumped: database, tablespace,
language(from-initdb), namespace(from-initdb)

Did I interpret the commit message correctly? The script gave these results:

Dumped: type, class, attribute, namespace(from-initdb)
Not dumped: database, tablespace, proc, language(from-initdb)

You interpreted the commit message correctly and in a number of cases
the correct results are generated, but there's an issue in the WHERE
clause being used for some of the object types.

I'm wondering whether it would be a slightly better design to treat
language(from-initdb) like language(in-extension). Likewise for namespaces.
The code apparently already exists to dump from-initdb namespace ACLs. Is
there a user interface design reason to want to distinguish the from-initdb
and in-extension cases?

That's relatively straight-forward to fix, but I'm going to put
together a series of TAP tests to go with these fixes. While I tested
various options and bits and pieces of the code while developing, this
really needs a proper test suite that runs through all of these
permutations with each change.

Sounds great. Thanks.

I'm planning to have that done by the end of the weekend.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#19)
1 attachment(s)

Noah, all,

* Noah Misch (noah@leadboat.com) wrote:

On Fri, Apr 22, 2016 at 12:31:41PM -0400, Stephen Frost wrote:

After looking through the code a bit, I realized that there are a lot of
object types which don't have ACLs at all but which exist in pg_catalog
and were being analyzed because the bitmask for pg_catalog included ACLs
and therefore was non-zero.

Clearing that bit for object types which don't have ACLs improved the
performance for empty databases quite a bit (from about 3s to a bit
under 1s on my laptop). That's a 42-line patch, with comment lines
being half of that, which I'll push once I've looked into the other
concerns which were brought up on this thread.

That's good news.

Attached patch-set includes this change in patch #2.

Patch #1 is the fix for the incorrect WHERE clause.

Much of the remaining inefficiancy is how we query for column
information one table at a time (that appears to be around 300ms of the
900ms or so total time). I'm certainly interested in improving that but
that would require adding more complex data structures to pg_dump than
what we use currently (we'd want to grab all of the columns we care
about in an entire schema and store it locally and then provide a way to
look up that information, etc), so I'm not sure it'd be appropriate to
do now.

I'm not sure, either; I'd need to see more to decide. If I were you, I would
draft a patch to the point where the community can see the complexity and the
performance change. That should be enough to inform the choice among moving
forward with the proposed complexity, soliciting other designs, reverting the
original changes, or accepting for 9.6 the slowdown as it stands at that time.
Other people may have more definite opinions already.

I'll look at doing this once I'm done with the regression test
improvements (see below).

* Noah Misch (noah@leadboat.com) wrote:

On Fri, Apr 22, 2016 at 08:24:53PM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

I wrote the attached test script to verify which types of ACLs dump/reload
covers. Based on the commit message, I expected these results:

Dumped: type, class, attribute, proc, largeobject_metadata,
foreign_data_wrapper, foreign_server,
language(in-extension), namespace(in-extension)
Not dumped: database, tablespace,
language(from-initdb), namespace(from-initdb)

Did I interpret the commit message correctly? The script gave these results:

Dumped: type, class, attribute, namespace(from-initdb)
Not dumped: database, tablespace, proc, language(from-initdb)

You interpreted the commit message correctly and in a number of cases
the correct results are generated, but there's an issue in the WHERE
clause being used for some of the object types.

I'm wondering whether it would be a slightly better design to treat
language(from-initdb) like language(in-extension). Likewise for namespaces.
The code apparently already exists to dump from-initdb namespace ACLs. Is
there a user interface design reason to want to distinguish the from-initdb
and in-extension cases?

Reviewing the code, we do record from-initdb namespace privileges, and
we also record in-extension namespace privileges (see
ExecGrant_Namespace()).

We also record from-initdb language ACLs (initdb.c:2071) and
in-extension language ACLs (see ExecGrant_Language()), so I'm not
entirely sure what, if any, issue exists here either.

For both, we also grab the ACL info vs. pg_init_privs in pg_dump.

The issue in these cases is a bit of an interesting one- they are not
part of a namespace; this patch was focused on allowing users to modify,
specifically, the ACLs of objects in the 'pg_catalog' namespace.

For languages, I believe that means that we simply need to modify the
selectDumpableProcLang() function to use the same default we use for the
'pg_catalog' namespace- DUMP_COMPONENT_ACL, instead of
DUMP_COMPONENT_NONE.

What's not clear to me is what, if any, issue there is with namespaces.

Certainly, in my testing at least, if you do:

REVOKE CREATE ON SCHEMA public FROM public;

Then you get the appropriate commands from pg_dump to implement the
resulting ACLs on the public schema. If you change the permissions back
to match what is there at initdb-time (or you just don't change them),
then there aren't any GRANT or REVOKE commands from pg_dump, but that's
correct, isn't it?

That's relatively straight-forward to fix, but I'm going to put
together a series of TAP tests to go with these fixes. While I tested
various options and bits and pieces of the code while developing, this
really needs a proper test suite that runs through all of these
permutations with each change.

Sounds great. Thanks.

I'm planning to have that done by the end of the weekend.

In the attached patch-set, patch #3 includes support for

src/bin/pg_dump: make check

implemented using the TAP testing system. There are a total of 360
tests, generally covering:

Various invalid sets of command-line options.

Valid command-line options (generally independently used):

(no options- defaults)
--clean
--clean --if-exists
--data-only
--format=c (tested with pg_restore)
--format=d (tested with pg_restore)
--format=t (tested with pg_restore)
--format=d --jobs=2 (tested with pg_restore)
--exclude-schema
--exclude-table
--no-privileges
--no-owner
--schema
--schema-only

Note that this is only including tests for basic schemas, tables, data,
and privileges, so far. I believe it's pretty obvious that we want to
include all object types and include testing of extensions, I just
haven't gotten there yet and figured now would be a good time to solicit
feedback on the approach I've used.

I'm not sure how valuable it is to test all the different combinations
of command-line options, though clearly some should be tested (eg:
include-schema, exclude table in that schema, and similar cases).

I'm planning to work on adding in other object types and, once that's
more-or-less complete, adding in a test for extensions and then adding
tests for GRANT/REVOKE on from-initdb and in-extension objects.

Thoughts?

Thanks!

Stephen

Attachments:

pg_dump_improvements_v1.patchtext/x-diff; charset=us-asciiDownload
From 7ed5716e6f02065c4ff0b92dd75bac765ac78b82 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 24 Apr 2016 23:59:23 -0400
Subject: [PATCH 1/3] Correct pg_dump WHERE clause for functions/aggregates

---
 src/bin/pg_dump/pg_dump.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 396c03d..d0f4113 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -4673,11 +4673,7 @@ getAggregates(Archive *fout, int *numAggs)
 						  "p.pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  username_subquery,
 						  acl_subquery->data,
 						  racl_subquery->data,
@@ -4923,11 +4919,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  acl_subquery->data,
 						  racl_subquery->data,
 						  initacl_subquery->data,
-- 
2.5.0


From c2fdc4354927466d77aae677e67ee5744adf8d92 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:00:15 -0400
Subject: [PATCH 2/3] Performance improvement for pg_dump

Do not try to dump objects which do not have ACLs when only ACLs are
being requested.
---
 src/bin/pg_dump/pg_dump.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d0f4113..384ba9e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -3729,6 +3729,9 @@ getExtensions(Archive *fout, int *numExtensions)
 
 		/* Decide whether we want to dump it */
 		selectDumpableExtension(&(extinfo[i]), dopt);
+
+		/* Extensions do not currently have ACLs. */
+		extinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4175,6 +4178,9 @@ getOperators(Archive *fout, int *numOprs)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(oprinfo[i].dobj), fout);
 
+		/* Operators do not currently have ACLs. */
+		oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (strlen(oprinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
 					  oprinfo[i].dobj.name);
@@ -4259,6 +4265,9 @@ getCollations(Archive *fout, int *numCollations)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(collinfo[i].dobj), fout);
+
+		/* Collations do not currently have ACLs. */
+		collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4340,6 +4349,9 @@ getConversions(Archive *fout, int *numConversions)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(convinfo[i].dobj), fout);
+
+		/* Conversions do not currently have ACLs. */
+		convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4413,6 +4425,9 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 
 		/* Decide whether we want to dump it */
 		selectDumpableAccessMethod(&(aminfo[i]), fout);
+
+		/* Access methods do not currently have ACLs. */
+		aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4506,6 +4521,9 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opcinfo[i].dobj), fout);
 
+		/* Op Classes do not currently have ACLs. */
+		opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opcinfo[i].rolname) == 0)
@@ -4594,6 +4612,9 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opfinfo[i].dobj), fout);
 
+		/* Extensions do not currently have ACLs. */
+		opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opfinfo[i].rolname) == 0)
@@ -6989,6 +7010,9 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(evtinfo[i].dobj), fout);
+
+		/* Event Triggers do not currently have ACLs. */
+		evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -7350,6 +7374,9 @@ getCasts(Archive *fout, int *numCasts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableCast(&(castinfo[i]), fout);
+
+		/* Casts do not currently have ACLs. */
+		castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8143,6 +8170,9 @@ getTSParsers(Archive *fout, int *numTSParsers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(prsinfo[i].dobj), fout);
+
+		/* Text Search Parsers do not currently have ACLs. */
+		prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8228,6 +8258,9 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(dictinfo[i].dobj), fout);
+
+		/* Text Search Dictionaries do not currently have ACLs. */
+		dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8305,6 +8338,9 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(tmplinfo[i].dobj), fout);
+
+		/* Text Search Templates do not currently have ACLs. */
+		tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8383,6 +8419,9 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(cfginfo[i].dobj), fout);
+
+		/* Text Search Configurations do not currently have ACLs. */
+		cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8793,6 +8832,9 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
 
 		/* Decide whether we want to dump it */
 		selectDumpableDefaultACL(&(daclinfo[i]), dopt);
+
+		/* Default ACLs do not currently have ACLs. */
+		daclinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
-- 
2.5.0


From 9e1042d76dc1e20869005bb9959c46d768cebb64 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:01:38 -0400
Subject: [PATCH 3/3] Add TAP tests for pg_dump

---
 src/bin/pg_dump/Makefile         |   3 +
 src/bin/pg_dump/t/001_basic.pl   |  42 +++
 src/bin/pg_dump/t/002_pg_dump.pl | 788 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 833 insertions(+)
 create mode 100644 src/bin/pg_dump/t/001_basic.pl
 create mode 100644 src/bin/pg_dump/t/002_pg_dump.pl

diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index 9596789..260804b 100644
--- a/src/bin/pg_dump/Makefile
+++ b/src/bin/pg_dump/Makefile
@@ -42,6 +42,9 @@ install: all installdirs
 installdirs:
 	$(MKDIR_P) '$(DESTDIR)$(bindir)'
 
+check:
+	$(prove_check)
+
 uninstall:
 	rm -f $(addprefix '$(DESTDIR)$(bindir)'/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X))
 
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
new file mode 100644
index 0000000..1411ef7
--- /dev/null
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -0,0 +1,42 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More tests => 15;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+#########################################
+# Basic checks
+
+program_help_ok('pg_dump');
+program_version_ok('pg_dump');
+program_options_handling_ok('pg_dump');
+
+#########################################
+# Test various invalid options and disallowed combinations
+# Doesn't require a PG instance to be set up, so do this first.
+
+command_exit_is([ 'pg_dump', 'qqq', 'abc' ],
+	1, 'pg_dump: too many command-line arguments (first is "asd")');
+
+command_exit_is([ 'pg_dump', '-s', '-a' ],
+	1, 'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '-c', '-a' ],
+	1, 'pg_dump: options -c/--clean and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '--inserts', '-o' ],
+	1, 'pg_dump: options --inserts/--column-inserts and -o/--oids cannot be used together');
+
+command_exit_is([ 'pg_dump', '--if-exists' ],
+	1, 'pg_dump: option --if-exists requires option -c/--clean');
+
+command_exit_is([ 'pg_dump', '-j' ],
+	1, 'pg_dump: option requires an argument -- \'j\'');
+
+command_exit_is([ 'pg_dump', '-j3' ],
+	1, 'pg_dump: parallel backup only supported by the directory format');
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
new file mode 100644
index 0000000..cb458a4
--- /dev/null
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -0,0 +1,788 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+my %pgdump_runs = (
+	clean => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean.sql",
+			'-c',
+			'postgres',
+		],
+	},
+	clean_if_exists => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean_if_exists.sql",
+			'-c',
+			'--if-exists',
+			'postgres',
+		],
+	},
+	data_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/data_only.sql",
+			'-a',
+			'postgres',
+		],
+	},
+	defaults => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/defaults.sql",
+			'postgres',
+		],
+	},
+	defaults_custom_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fc',
+			'-f', "$tempdir/defaults_custom_format.dump",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-Fc',
+			'-f', "$tempdir/defaults_custom_format.sql",
+			"$tempdir/defaults_custom_format.dump",
+		],
+	},
+	defaults_dir_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-f', "$tempdir/defaults_dir_format",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-Fd',
+			'-f', "$tempdir/defaults_dir_format.sql",
+			"$tempdir/defaults_dir_format",
+		],
+	},
+	defaults_parallel => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-j2',
+			'-f', "$tempdir/defaults_parallel",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-Fd',
+			'-f', "$tempdir/defaults_parallel.sql",
+			"$tempdir/defaults_parallel",
+		],
+	},
+	defaults_tar_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Ft',
+			'-f', "$tempdir/defaults_tar_format.tar",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-Ft',
+			'-f', "$tempdir/defaults_tar_format.sql",
+			"$tempdir/defaults_tar_format.tar",
+		],
+	},
+	exclude_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_dump_test_schema.sql",
+			'-N', 'dump_test',
+			'postgres',
+		],
+	},
+	exclude_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table.sql",
+			'-T', 'dump_test.test_table',
+			'postgres',
+		],
+	},
+	exclude_test_table_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table_data.sql",
+			'--exclude-table-data=dump_test.test_table',
+			'postgres',
+		],
+	},
+	no_privs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_privs.sql",
+			'-x',
+			'postgres',
+		],
+	},
+	no_owner => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_owner.sql",
+			'-O',
+			'postgres',
+		],
+	},
+	only_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_schema.sql",
+			'-n', 'dump_test',
+			'postgres',
+		],
+	},
+	only_dump_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_table.sql",
+			'-t', 'dump_test.test_table',
+			'postgres',
+		],
+	},
+	schema_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/schema_only.sql",
+			'-s',
+			'postgres',
+		],
+	},
+);
+
+my %tests = (
+	'ALTER SCHEMA dump_test OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test OWNER TO .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER SCHEMA dump_test_second_schema OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test_second_schema OWNER TO .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_table OWNER TO .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_second_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_second_table OWNER TO .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_third_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_third_table OWNER TO .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER ... OWNER commands' => { # catch-all for ALTER ... OWNER
+		regexp => qr/^ALTER .* OWNER TO .*;$/m,
+		like => { }, # use more-specific options above
+		unlike => {
+			data_only => 1,
+			no_owner => 1,
+		},
+	},
+	'COMMENT ON DATABASE postgres' => {
+		regexp => qr/^COMMENT ON DATABASE postgres IS .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT ON EXTENSION plpgsql' => {
+		regexp => qr/^COMMENT ON EXTENSION plpgsql IS .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT commands' => { # catch-all for COMMENTs
+		regexp => qr/^COMMENT ON /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			data_only => 1,
+		},
+	},
+	'COPY test_table' => {
+		regexp => qr/^COPY test_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			data_only => 1,
+			defaults => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+		},
+	},
+	'COPY test_second_table' => {
+		regexp => qr/^COPY test_second_table \(col1, col2\) FROM stdin;\n(?:\d\t\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY test_third_table' => {
+		regexp => qr/^COPY test_third_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY ... commands' => { # catch-all for COPY
+		regexp => qr/^COPY /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			schema_only => 1,
+		},
+	},
+	'CREATE EXTENSION ... plpgsql' => {
+		regexp => qr/^CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test' => {
+		regexp => qr/^CREATE SCHEMA dump_test;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test_second_schema' => {
+		regexp => qr/^CREATE SCHEMA dump_test_second_schema;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'CREATE TABLE test_table' => {
+		regexp => qr/^CREATE TABLE test_table \(\n\s+col1 integer\n\);$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'CREATE TABLE test_second_table' => {
+		regexp => qr/^CREATE TABLE test_second_table \(\n\s+col1 integer,\n\s+col2 text\n\);$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'CREATE TABLE test_third_table' => {
+		regexp => qr/^CREATE TABLE test_third_table \(\n\s+col1 integer\n\);$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'CREATE ... commands' => { # catch-all for CREATE
+		regexp => qr/^CREATE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			data_only => 1,
+		},
+	},
+	'DROP EXTENSION plpgsql' => {
+		regexp => qr/^DROP EXTENSION plpgsql;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test' => {
+		regexp => qr/^DROP SCHEMA dump_test;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA dump_test_second_schema;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_second_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_second_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_third_table' => {
+		regexp => qr/^DROP TABLE dump_test_second_schema\.test_third_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP EXTENSION IF EXISTS plpgsql' => {
+		regexp => qr/^DROP EXTENSION IF EXISTS plpgsql;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test_second_schema;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_second_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_second_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_third_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test_second_schema\.test_third_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP ... commands' => { # catch-all for DROP
+		regexp => qr/^DROP /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+		},
+	},
+	'GRANT USAGE ON SCHEMA dump_test_second_schema' => {
+		regexp => qr/^GRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'GRANT SELECT ON TABLE test_table' => {
+		regexp => qr/^GRANT SELECT ON TABLE test_table TO dump_test;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'GRANT INSERT(col1) ON TABLE test_second_table' => {
+		regexp => qr/^GRANT INSERT\(col1\) ON TABLE test_second_table TO dump_test;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'GRANT commands' => { # catch-all for GRANT commands
+		regexp => qr/^GRANT /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			data_only => 1,
+			no_privs => 1,
+		},
+	},
+	'REVOKE commands' => { # catch-all for REVOKE commands
+		regexp => qr/^REVOKE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			data_only => 1,
+			no_privs => 1,
+		},
+	},
+);
+
+#########################################
+# Create a PG instance to test actually dumping from
+
+my $node = get_new_node('main');
+$node->init;
+$node->start;
+
+#########################################
+# Set up schemas, tables, etc, to be dumped.
+
+$node->safe_psql('postgres',
+	    'CREATE ROLE dump_test; '
+	  . 'CREATE SCHEMA dump_test; '
+	  . 'CREATE TABLE dump_test.test_table (col1 int); '
+	  . 'INSERT INTO dump_test.test_table (col1) '
+	  . 'SELECT generate_series FROM generate_series(1,9);'
+	  . 'GRANT SELECT ON TABLE dump_test.test_table TO dump_test;'
+	  . 'CREATE TABLE dump_test.test_second_table (col1 int, col2 text); '
+	  . 'INSERT INTO dump_test.test_second_table (col1, col2) '
+	  . 'SELECT generate_series, generate_series::text FROM generate_series(1,9);'
+	  . 'GRANT INSERT (col1) ON TABLE dump_test.test_second_table TO dump_test;'
+	  . 'CREATE SCHEMA dump_test_second_schema; '
+	  . 'GRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;'
+	  . 'CREATE TABLE dump_test_second_schema.test_third_table (col1 int); '
+	  . 'INSERT INTO dump_test_second_schema.test_third_table (col1) '
+	  . 'SELECT generate_series FROM generate_series(1,9);'
+  );
+
+my $port = $node->port;
+
+# Start with 1 because of non-existant database test below
+my $num_tests = 1;
+
+foreach my $run (sort keys %pgdump_runs) {
+	my $test_key = $run;
+
+	# Each run of pg_dump is a test itself
+	$num_tests++;
+
+	# If there is a restore cmd, that's another test
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$num_tests++;
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	# Then count all the tests run against each run
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			$num_tests++;
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			$num_tests++;
+		}
+	}
+}
+plan tests => $num_tests;
+
+#########################################
+# Test connecting to a non-existant database
+
+command_exit_is([ 'pg_dump', '-p', "$port", 'qqq' ],
+	1, 'pg_dump: [archiver (db)] connection to database "qqq" failed: FATAL:  database "qqq" does not exist');
+
+#########################################
+# Run all runs
+
+foreach my $run (sort keys %pgdump_runs) {
+
+	my $test_key = $run;
+
+	$node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs");
+
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$node->command_ok(\@{ $pgdump_runs{$run}->{restore_cmd} }, "$run: pg_restore runs");
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	my $output_file = slurp_file("$tempdir/${run}.sql");
+
+	#########################################
+	# Run all tests where this run is included
+	# as either a 'like' or 'unlike' test.
+
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			like($output_file, $tests{$test}->{regexp}, "$run: dumps $test");
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			unlike($output_file, $tests{$test}->{regexp}, "$run: does not dump $test");
+		}
+	}
+}
+
+#########################################
+# Clean up
+
+$node->safe_psql('postgres',
+	    'DROP SCHEMA dump_test CASCADE; '
+	  . 'DROP SCHEMA dump_test_second_schema CASCADE; '
+	  . 'DROP ROLE dump_test; '
+  );
+
+$node->stop('fast');
-- 
2.5.0

#21Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#20)

On Mon, Apr 25, 2016 at 12:39:09AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Fri, Apr 22, 2016 at 12:31:41PM -0400, Stephen Frost wrote:

After looking through the code a bit, I realized that there are a lot of
object types which don't have ACLs at all but which exist in pg_catalog
and were being analyzed because the bitmask for pg_catalog included ACLs
and therefore was non-zero.

Clearing that bit for object types which don't have ACLs improved the
performance for empty databases quite a bit (from about 3s to a bit
under 1s on my laptop). That's a 42-line patch, with comment lines
being half of that, which I'll push once I've looked into the other
concerns which were brought up on this thread.

That's good news.

Attached patch-set includes this change in patch #2.

Timings for the 100-database pg_dumpall:

HEAD: 131s
HEAD+patch: 33s
9.5: 8.6s

Nice improvement for such a simple patch.

Patch #1 is the fix for the incorrect WHERE clause.

I confirmed that this fixed dumping of the function ACL in my test case.

For languages, I believe that means that we simply need to modify the
selectDumpableProcLang() function to use the same default we use for the
'pg_catalog' namespace- DUMP_COMPONENT_ACL, instead of
DUMP_COMPONENT_NONE.

Makes sense.

What's not clear to me is what, if any, issue there is with namespaces.

As far as I know, none. The current behavior doesn't match the commit
message, but I think the current behavior is better.

Certainly, in my testing at least, if you do:

REVOKE CREATE ON SCHEMA public FROM public;

Then you get the appropriate commands from pg_dump to implement the
resulting ACLs on the public schema. If you change the permissions back
to match what is there at initdb-time (or you just don't change them),
then there aren't any GRANT or REVOKE commands from pg_dump, but that's
correct, isn't it?

Good question. I think it's fine and possibly even optimal. One can imagine
other designs that remember whether any GRANT or REVOKE has happened since
initdb, but I see no definite reason to prefer that alternative.

In the attached patch-set, patch #3 includes support for

src/bin/pg_dump: make check

implemented using the TAP testing system. There are a total of 360
tests, generally covering:

I like the structure of this test suite.

+# Start with 1 because of non-existant database test below
+# Test connecting to a non-existant database

Spelling.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#22Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#20)

A later thought:

On Mon, Apr 25, 2016 at 12:39:09AM -0400, Stephen Frost wrote:

src/bin/pg_dump: make check

implemented using the TAP testing system. There are a total of 360
tests, generally covering:

Various invalid sets of command-line options.

Valid command-line options (generally independently used):

(no options- defaults)
--clean
--clean --if-exists
--data-only
--format=c (tested with pg_restore)
--format=d (tested with pg_restore)
--format=t (tested with pg_restore)
--format=d --jobs=2 (tested with pg_restore)
--exclude-schema
--exclude-table
--no-privileges
--no-owner
--schema
--schema-only

Note that this is only including tests for basic schemas, tables, data,
and privileges, so far. I believe it's pretty obvious that we want to
include all object types and include testing of extensions, I just
haven't gotten there yet and figured now would be a good time to solicit
feedback on the approach I've used.

I'm not sure how valuable it is to test all the different combinations
of command-line options, though clearly some should be tested (eg:
include-schema, exclude table in that schema, and similar cases).

You mention that you test valid options independently. Keep an eye out for
good opportunities to save runtime by testing multiple options per invocation.
To give one example, --exclude-table seems fairly independent of --format;
maybe those could test as a group. That complicates the suite, but saving ten
or more seconds might justify the complexity.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#22)

Noah,

On Wednesday, April 27, 2016, Noah Misch <noah@leadboat.com> wrote:

A later thought:

On Mon, Apr 25, 2016 at 12:39:09AM -0400, Stephen Frost wrote:

src/bin/pg_dump: make check

implemented using the TAP testing system. There are a total of 360
tests, generally covering:

Various invalid sets of command-line options.

Valid command-line options (generally independently used):

(no options- defaults)
--clean
--clean --if-exists
--data-only
--format=c (tested with pg_restore)
--format=d (tested with pg_restore)
--format=t (tested with pg_restore)
--format=d --jobs=2 (tested with pg_restore)
--exclude-schema
--exclude-table
--no-privileges
--no-owner
--schema
--schema-only

Note that this is only including tests for basic schemas, tables, data,
and privileges, so far. I believe it's pretty obvious that we want to
include all object types and include testing of extensions, I just
haven't gotten there yet and figured now would be a good time to solicit
feedback on the approach I've used.

I'm not sure how valuable it is to test all the different combinations
of command-line options, though clearly some should be tested (eg:
include-schema, exclude table in that schema, and similar cases).

You mention that you test valid options independently. Keep an eye out for
good opportunities to save runtime by testing multiple options per
invocation.
To give one example, --exclude-table seems fairly independent of --format;
maybe those could test as a group. That complicates the suite, but saving
ten
or more seconds might justify the complexity.

That thought had occurred to me also and I began combining some options,
though I could probably do more to reduce the runtime:

The current challenge I've been trying to find a solution to is testing the
extension handling. Only core extensions (plpgsql, plperl, etc) are
available when the TAP tests are running for pg_dump, it seems. I certainly
don't want to add a testing extension in such a way that it would get
installed for users, but it doesn't seem obvious how to create an extension
from another directory or to even find the directory where I could write
the control and SQL files into to use.

Any thoughts on that would certainly be welcome.

Thanks!

Stephen

#24Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Stephen Frost (#23)

Stephen Frost wrote:

The current challenge I've been trying to find a solution to is testing the
extension handling. Only core extensions (plpgsql, plperl, etc) are
available when the TAP tests are running for pg_dump, it seems. I certainly
don't want to add a testing extension in such a way that it would get
installed for users, but it doesn't seem obvious how to create an extension
from another directory or to even find the directory where I could write
the control and SQL files into to use.

Any thoughts on that would certainly be welcome.

Did you notice the src/test/modules/test_extensions thingy? Supposedly
we do try pg_dump with custom extensions there.

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25Stephen Frost
sfrost@snowman.net
In reply to: Alvaro Herrera (#24)

Alvaro,

On Wednesday, April 27, 2016, Alvaro Herrera <alvherre@2ndquadrant.com>
wrote:

Stephen Frost wrote:

The current challenge I've been trying to find a solution to is testing

the

extension handling. Only core extensions (plpgsql, plperl, etc) are
available when the TAP tests are running for pg_dump, it seems. I

certainly

don't want to add a testing extension in such a way that it would get
installed for users, but it doesn't seem obvious how to create an

extension

from another directory or to even find the directory where I could write
the control and SQL files into to use.

Any thoughts on that would certainly be welcome.

Did you notice the src/test/modules/test_extensions thingy? Supposedly
we do try pg_dump with custom extensions there.

Hmm. I think the issue I was having is that I wanted to test the extension
handling in pg_dump's 'make check' run, but that's before any of those
extension pieces are installed or tested.

However, perhaps I can test the pg_dump parts as part of the extension
'make check' runs instead. Will check it out.

Thanks!

Stephen

#26Robert Haas
robertmhaas@gmail.com
In reply to: Peter Geoghegan (#15)

On Fri, Apr 22, 2016 at 3:30 AM, Peter Geoghegan <pg@heroku.com> wrote:

On Fri, Apr 22, 2016 at 12:25 AM, Noah Misch <noah@leadboat.com> wrote:

Folks run clusters with ~1000 databases; we previously accepted at least one
complex performance improvement[1] based on that use case. On the faster of
the two machines I tested, the present thread's commits slowed "pg_dumpall
--schema-only --binary-upgrade" by 1-2s per database. That doubles pg_dump
runtime against the installcheck regression database. A run against a cluster
of one hundred empty databases slowed fifteen-fold, from 8.6s to 131s.
"pg_upgrade -j50" probably will keep things tolerable for the 1000-database
case, but the performance regression remains jarring. I think we should not
release 9.6 with pg_dump performance as it stands today.

As someone that is responsible for many such clusters, I strongly agree.

Stephen: This is a CRITICAL ISSUE. Unless I'm missing something, this
hasn't gone anywhere in well over a week, and we're wrapping beta next
Monday. Please fix it.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#21)
1 attachment(s)

Noah,

* Noah Misch (noah@leadboat.com) wrote:

On Mon, Apr 25, 2016 at 12:39:09AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Fri, Apr 22, 2016 at 12:31:41PM -0400, Stephen Frost wrote:

After looking through the code a bit, I realized that there are a lot of
object types which don't have ACLs at all but which exist in pg_catalog
and were being analyzed because the bitmask for pg_catalog included ACLs
and therefore was non-zero.

Clearing that bit for object types which don't have ACLs improved the
performance for empty databases quite a bit (from about 3s to a bit
under 1s on my laptop). That's a 42-line patch, with comment lines
being half of that, which I'll push once I've looked into the other
concerns which were brought up on this thread.

That's good news.

Attached patch-set includes this change in patch #2.

Timings for the 100-database pg_dumpall:

HEAD: 131s
HEAD+patch: 33s
9.5: 8.6s

Nice improvement for such a simple patch.

Patch #2 in the attached patchset includes that improvement and a
further one which returns the performance to very close to 9.5. This is
done by checking for any changed ACLs for a given table (the table-level
and column-level ones) and removing the ACL component if there haven't
been any changes.

Patch #1 is the fix for the incorrect WHERE clause.

I confirmed that this fixed dumping of the function ACL in my test case.

This patch is unchanged.

For languages, I believe that means that we simply need to modify the
selectDumpableProcLang() function to use the same default we use for the
'pg_catalog' namespace- DUMP_COMPONENT_ACL, instead of
DUMP_COMPONENT_NONE.

Makes sense.

This is now being tested in the TAP testing for pg_dump that I've been
working on (patch #3). Fixing this issue was a bit more complicated
because of cases like plpgsql, which is a from-initdb extension, but we
still want to dump out any changes to plpgsql that the user has made, so
we have to dump ACLs for from-initdb extension objects, if they've been
changed.

Those fixes are included in patch #2 in the patchset.

What's not clear to me is what, if any, issue there is with namespaces.

As far as I know, none. The current behavior doesn't match the commit
message, but I think the current behavior is better.

Great. No changes have been made to how namespaces are handled.

Certainly, in my testing at least, if you do:

REVOKE CREATE ON SCHEMA public FROM public;

Then you get the appropriate commands from pg_dump to implement the
resulting ACLs on the public schema. If you change the permissions back
to match what is there at initdb-time (or you just don't change them),
then there aren't any GRANT or REVOKE commands from pg_dump, but that's
correct, isn't it?

Good question. I think it's fine and possibly even optimal. One can imagine
other designs that remember whether any GRANT or REVOKE has happened since
initdb, but I see no definite reason to prefer that alternative.

Neither do I.

In the attached patch-set, patch #3 includes support for

src/bin/pg_dump: make check

implemented using the TAP testing system. There are a total of 360
tests, generally covering:

I like the structure of this test suite.

Great. I've added a whole ton more tests, added more options to various
pg_dump runs to test more options with fewer runs (though there are
still quite a few...) and added more objects to be created. Also added
a bunch of comments to describe how the test suite is set up.

+# Start with 1 because of non-existant database test below
+# Test connecting to a non-existant database

Spelling.

Fixed.

The test suite is now covering 57% of pg_dump.c. I was hoping to get
that number higher, but time marches on and more tests can certainly be
added later.

I'm planning to do another review of this patch-set and do testing
against back-branches back to 7.4. Barring any issues or objections,
I'll commit this tomorrow to address the performance concerns and to add
in the test suite.

On my system, the test suite takes about 15 seconds to run, which
includes setting up the cluster, creating all the objects, and then
running the pg_dump runs and checking the results. All told, in those
15 seconds, 1,213 tests are run.

Thanks!

Stephen

Attachments:

pg_dump_improvements_v2.patchtext/x-diff; charset=us-asciiDownload
From d8eebb233187bb4fa46c5e90d75db680d991f801 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 24 Apr 2016 23:59:23 -0400
Subject: [PATCH 1/3] Correct pg_dump WHERE clause for functions/aggregates

---
 src/bin/pg_dump/pg_dump.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d3f5157..bb33075 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -4673,11 +4673,7 @@ getAggregates(Archive *fout, int *numAggs)
 						  "p.pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  username_subquery,
 						  acl_subquery->data,
 						  racl_subquery->data,
@@ -4923,11 +4919,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  acl_subquery->data,
 						  racl_subquery->data,
 						  initacl_subquery->data,
-- 
2.5.0


From 7519a5c222fe4bf5dc832b266c90ddb7b171122f Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:00:15 -0400
Subject: [PATCH 2/3] pg_dump performance and other fixes

Do not try to dump objects which do not have ACLs when only ACLs are
being requested.

When limiting the components to dump for an extension, consider what
components have been asked for.

Correct defaultACLs to use 'dump_contains' instead of 'dump'

Use DUMP_COMPONENT_ACL for from-initdb objects, to allow users to
change their ACLs, should they wish to.
---
 src/bin/pg_dump/pg_dump.c | 176 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 149 insertions(+), 27 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index bb33075..d826b4d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1297,14 +1297,17 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout)
 	 * contents rather than replace the extension contents with something
 	 * different.
 	 */
-	if (!fout->dopt->binary_upgrade && fout->remoteVersion >= 90600)
-		dobj->dump = DUMP_COMPONENT_ACL |
-			DUMP_COMPONENT_SECLABEL |
-			DUMP_COMPONENT_POLICY;
-	else if (!fout->dopt->binary_upgrade)
-		dobj->dump = DUMP_COMPONENT_NONE;
-	else
+	if (fout->dopt->binary_upgrade)
 		dobj->dump = ext->dobj.dump;
+	else
+	{
+		if (fout->remoteVersion < 90600)
+			dobj->dump = DUMP_COMPONENT_NONE;
+		else
+			dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
+					DUMP_COMPONENT_SECLABEL | DUMP_COMPONENT_POLICY);
+
+	}
 
 	return true;
 }
@@ -1452,7 +1455,7 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 
 	if (dinfo->dobj.namespace)
 		/* default ACLs are considered part of the namespace */
-		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
+		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
 	else
 		dinfo->dobj.dump = dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
@@ -1473,6 +1476,10 @@ selectDumpableCast(CastInfo *cast, Archive *fout)
 	if (checkExtensionMembership(&cast->dobj, fout))
 		return;					/* extension membership overrides all else */
 
+	/*
+	 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
+	 * support ACLs currently.
+	 */
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
@@ -1494,11 +1501,23 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
 	if (checkExtensionMembership(&plang->dobj, fout))
 		return;					/* extension membership overrides all else */
 
-	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
+	/*
+	 * Only include procedural languages when we are dumping everything.
+	 *
+	 * For from-initdb procedural languages, only include ACLs, as we do for
+	 * the pg_catalog namespace.  We need this because procedural languages do
+	 * not live in any namespace.
+	 */
+	if (!fout->dopt->include_everything)
 		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = fout->dopt->include_everything ?
-			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+	{
+		if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
+			plang->dobj.dump = fout->remoteVersion < 90600 ?
+				DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
+		else
+			plang->dobj.dump = DUMP_COMPONENT_ALL;
+	}
 }
 
 /*
@@ -1515,6 +1534,10 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 	if (checkExtensionMembership(&method->dobj, fout))
 		return;					/* extension membership overrides all else */
 
+	/*
+	 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
+	 * they do not support ACLs currently.
+	 */
 	if (method->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		method->dobj.dump = DUMP_COMPONENT_NONE;
 	else
@@ -1535,11 +1558,17 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 static void
 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 {
+	/*
+	 * Use DUMP_COMPONENT_ACL for from-initdb extensions, to allow users
+	 * to change permissions on those objects, if they wish to, and have
+	 * those changes preserved.
+	 */
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		extinfo->dobj.dump = DUMP_COMPONENT_ACL;
 	else
-		extinfo->dobj.dump = dopt->include_everything ?
-			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+		extinfo->dobj.dump = extinfo->dobj.dump_contains =
+			dopt->include_everything ?  DUMP_COMPONENT_ALL :
+				DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -4175,6 +4204,9 @@ getOperators(Archive *fout, int *numOprs)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(oprinfo[i].dobj), fout);
 
+		/* Operators do not currently have ACLs. */
+		oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (strlen(oprinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
 					  oprinfo[i].dobj.name);
@@ -4259,6 +4291,9 @@ getCollations(Archive *fout, int *numCollations)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(collinfo[i].dobj), fout);
+
+		/* Collations do not currently have ACLs. */
+		collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4340,6 +4375,9 @@ getConversions(Archive *fout, int *numConversions)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(convinfo[i].dobj), fout);
+
+		/* Conversions do not currently have ACLs. */
+		convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4413,6 +4451,9 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 
 		/* Decide whether we want to dump it */
 		selectDumpableAccessMethod(&(aminfo[i]), fout);
+
+		/* Access methods do not currently have ACLs. */
+		aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4506,6 +4547,9 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opcinfo[i].dobj), fout);
 
+		/* Op Classes do not currently have ACLs. */
+		opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opcinfo[i].rolname) == 0)
@@ -4594,6 +4638,9 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opfinfo[i].dobj), fout);
 
+		/* Extensions do not currently have ACLs. */
+		opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opfinfo[i].rolname) == 0)
@@ -5123,6 +5170,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_toastreloptions;
 	int			i_reloftype;
 	int			i_relpages;
+	int			i_changed_acl;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
@@ -5154,6 +5202,11 @@ getTables(Archive *fout, int *numTables)
 		PQExpBuffer initacl_subquery = createPQExpBuffer();
 		PQExpBuffer initracl_subquery = createPQExpBuffer();
 
+		PQExpBuffer attacl_subquery = createPQExpBuffer();
+		PQExpBuffer attracl_subquery = createPQExpBuffer();
+		PQExpBuffer attinitacl_subquery = createPQExpBuffer();
+		PQExpBuffer attinitracl_subquery = createPQExpBuffer();
+
 		/*
 		 * Left join to pick up dependency info linking sequences to their
 		 * owning column, if any (note this dependency is AUTO as of 8.2)
@@ -5167,6 +5220,10 @@ getTables(Archive *fout, int *numTables)
 				 "CASE WHEN c.relkind = 'S' THEN 's' ELSE 'r' END::\"char\"",
 						dopt->binary_upgrade);
 
+		buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
+						attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
+						dopt->binary_upgrade);
+
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
 						  "%s AS relacl, %s as rrelacl, "
@@ -5188,7 +5245,17 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON"
+						  "(c.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND pip.objsubid = at.attnum)"
+						  "WHERE at.attrelid = c.oid AND ("
+						  "%s IS NOT NULL "
+						  "OR %s IS NOT NULL "
+						  "OR %s IS NOT NULL "
+						  "OR %s IS NOT NULL"
+						  "))"
+						  "AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5207,6 +5274,10 @@ getTables(Archive *fout, int *numTables)
 						  initacl_subquery->data,
 						  initracl_subquery->data,
 						  username_subquery,
+						  attacl_subquery->data,
+						  attracl_subquery->data,
+						  attinitacl_subquery->data,
+						  attinitracl_subquery->data,
 						  RELKIND_SEQUENCE,
 						  RELKIND_RELATION, RELKIND_SEQUENCE,
 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
@@ -5216,6 +5287,11 @@ getTables(Archive *fout, int *numTables)
 		destroyPQExpBuffer(racl_subquery);
 		destroyPQExpBuffer(initacl_subquery);
 		destroyPQExpBuffer(initracl_subquery);
+
+		destroyPQExpBuffer(attacl_subquery);
+		destroyPQExpBuffer(attracl_subquery);
+		destroyPQExpBuffer(attinitacl_subquery);
+		destroyPQExpBuffer(attinitracl_subquery);
 	}
 	else if (fout->remoteVersion >= 90500)
 	{
@@ -5245,7 +5321,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5290,7 +5367,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5335,7 +5413,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5378,7 +5457,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5421,7 +5501,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5463,7 +5544,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5505,7 +5587,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5546,7 +5629,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5586,7 +5670,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5623,7 +5708,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5655,7 +5741,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5695,7 +5782,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "WHERE relkind IN ('%c', '%c') "
 						  "ORDER BY oid",
@@ -5754,6 +5842,7 @@ getTables(Archive *fout, int *numTables)
 	i_checkoption = PQfnumber(res, "checkoption");
 	i_toastreloptions = PQfnumber(res, "toast_reloptions");
 	i_reloftype = PQfnumber(res, "reloftype");
+	i_changed_acl = PQfnumber(res, "changed_acl");
 
 	if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
 	{
@@ -5835,6 +5924,21 @@ getTables(Archive *fout, int *numTables)
 		else
 			selectDumpableTable(&tblinfo[i], fout);
 
+		/*
+		 * If the table-level and all column-level ACLs for this table are
+		 * unchanged, then we don't need to worry about including the ACLs
+		 * for this table.  If any column-level ACLs have been changed, the
+		 * 'changed_acl' column from the query will indicate that.
+		 *
+		 * This can result in a significant performance improvement in cases
+		 * where we are only looking to dump out the ACL (eg: pg_catalog).
+		 */
+		if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
+			PQgetisnull(res, i, i_initrelacl) &&
+			PQgetisnull(res, i, i_initrrelacl) &&
+			strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
+			tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
@@ -6989,6 +7093,9 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(evtinfo[i].dobj), fout);
+
+		/* Event Triggers do not currently have ACLs. */
+		evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -7350,6 +7457,9 @@ getCasts(Archive *fout, int *numCasts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableCast(&(castinfo[i]), fout);
+
+		/* Casts do not currently have ACLs. */
+		castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8143,6 +8253,9 @@ getTSParsers(Archive *fout, int *numTSParsers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(prsinfo[i].dobj), fout);
+
+		/* Text Search Parsers do not currently have ACLs. */
+		prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8228,6 +8341,9 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(dictinfo[i].dobj), fout);
+
+		/* Text Search Dictionaries do not currently have ACLs. */
+		dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8305,6 +8421,9 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(tmplinfo[i].dobj), fout);
+
+		/* Text Search Templates do not currently have ACLs. */
+		tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8383,6 +8502,9 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(cfginfo[i].dobj), fout);
+
+		/* Text Search Configurations do not currently have ACLs. */
+		cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
-- 
2.5.0


From 09bd079afad3729c5d92ab2d6a0258811500a3d0 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:01:38 -0400
Subject: [PATCH 3/3] Add TAP tests for pg_dump

---
 src/bin/pg_dump/Makefile         |    3 +
 src/bin/pg_dump/pg_dump.c        |    2 +-
 src/bin/pg_dump/t/001_basic.pl   |   42 +
 src/bin/pg_dump/t/002_pg_dump.pl | 2010 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 2056 insertions(+), 1 deletion(-)
 create mode 100644 src/bin/pg_dump/t/001_basic.pl
 create mode 100644 src/bin/pg_dump/t/002_pg_dump.pl

diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index 9596789..260804b 100644
--- a/src/bin/pg_dump/Makefile
+++ b/src/bin/pg_dump/Makefile
@@ -42,6 +42,9 @@ install: all installdirs
 installdirs:
 	$(MKDIR_P) '$(DESTDIR)$(bindir)'
 
+check:
+	$(prove_check)
+
 uninstall:
 	rm -f $(addprefix '$(DESTDIR)$(bindir)'/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X))
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d826b4d..457ba58 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1564,7 +1564,7 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 	 * those changes preserved.
 	 */
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = DUMP_COMPONENT_ACL;
+		extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
 	else
 		extinfo->dobj.dump = extinfo->dobj.dump_contains =
 			dopt->include_everything ?  DUMP_COMPONENT_ALL :
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
new file mode 100644
index 0000000..1411ef7
--- /dev/null
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -0,0 +1,42 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More tests => 15;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+#########################################
+# Basic checks
+
+program_help_ok('pg_dump');
+program_version_ok('pg_dump');
+program_options_handling_ok('pg_dump');
+
+#########################################
+# Test various invalid options and disallowed combinations
+# Doesn't require a PG instance to be set up, so do this first.
+
+command_exit_is([ 'pg_dump', 'qqq', 'abc' ],
+	1, 'pg_dump: too many command-line arguments (first is "asd")');
+
+command_exit_is([ 'pg_dump', '-s', '-a' ],
+	1, 'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '-c', '-a' ],
+	1, 'pg_dump: options -c/--clean and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '--inserts', '-o' ],
+	1, 'pg_dump: options --inserts/--column-inserts and -o/--oids cannot be used together');
+
+command_exit_is([ 'pg_dump', '--if-exists' ],
+	1, 'pg_dump: option --if-exists requires option -c/--clean');
+
+command_exit_is([ 'pg_dump', '-j' ],
+	1, 'pg_dump: option requires an argument -- \'j\'');
+
+command_exit_is([ 'pg_dump', '-j3' ],
+	1, 'pg_dump: parallel backup only supported by the directory format');
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
new file mode 100644
index 0000000..900330a
--- /dev/null
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -0,0 +1,2010 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+###############################################################
+# Definition of the pg_dump runs to make.
+#
+# Each of these runs are named and those names are used below
+# to define how each test should (or shouldn't) treat a result
+# from a given run.
+#
+# test_key indicates that a given run should simply use the same
+# set of like/unlike tests as another run, and which run that is.
+#
+# dump_cmd is the pg_dump command to run, which is an array of
+# the full command and arguments to run.  Note that this is run
+# using $node->command_ok(), so the port does not need to be
+# specified and is pulled from $PGPORT, which is set by the
+# PostgresNode system.
+#
+# restore_cmd is the pg_restore command to run, if any.  Note
+# that this should generally be used when the pg_dump goes to
+# a non-text file and that the restore can then be used to
+# generate a text file to run through the tests from the
+# non-text file generated by pg_dump.
+#
+# TODO: Have pg_restore actually restore to an independent
+# database and then pg_dump *that* database (or something along
+# those lines) to validate that part of the process.
+
+my %pgdump_runs = (
+	binary_upgrade => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/binary_upgrade.sql",
+			'--schema-only',
+			'--binary-upgrade',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean.sql",
+			'-c',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean_if_exists => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean_if_exists.sql",
+			'-c',
+			'--if-exists',
+			'-E', 'UTF8', # no-op, just tests that option is accepted
+			'postgres',
+		],
+	},
+	column_inserts => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/column_inserts.sql",
+			'-a',
+			'--column-inserts',
+			'postgres',
+		],
+	},
+	createdb => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/createdb.sql",
+			'-C',
+			'-R', # no-op, just for testing
+			'postgres',
+		],
+	},
+	data_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/data_only.sql",
+			'-a',
+			'-v', # no-op, just make sure it works
+			'postgres',
+		],
+	},
+	defaults => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/defaults.sql",
+			'postgres',
+		],
+	},
+	defaults_custom_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fc',
+			'-Z6',
+			'-f', "$tempdir/defaults_custom_format.dump",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_custom_format.sql",
+			"$tempdir/defaults_custom_format.dump",
+		],
+	},
+	defaults_dir_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-f', "$tempdir/defaults_dir_format",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_dir_format.sql",
+			"$tempdir/defaults_dir_format",
+		],
+	},
+	defaults_parallel => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-j2',
+			'-f', "$tempdir/defaults_parallel",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_parallel.sql",
+			"$tempdir/defaults_parallel",
+		],
+	},
+	defaults_tar_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Ft',
+			'-f', "$tempdir/defaults_tar_format.tar",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_tar_format.sql",
+			"$tempdir/defaults_tar_format.tar",
+		],
+	},
+	exclude_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_dump_test_schema.sql",
+			'-N', 'dump_test',
+			'postgres',
+		],
+	},
+	exclude_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table.sql",
+			'-T', 'dump_test.test_table',
+			'postgres',
+		],
+	},
+	exclude_test_table_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table_data.sql",
+			'--exclude-table-data=dump_test.test_table',
+			'postgres',
+		],
+	},
+	pg_dumpall_globals => {
+		dump_cmd => [
+			'pg_dumpall',
+			'-f', "$tempdir/pg_dumpall_globals.sql",
+			'-g',
+		],
+	},
+	no_privs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_privs.sql",
+			'-x',
+			'postgres',
+		],
+	},
+	no_owner => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_owner.sql",
+			'-O',
+			'postgres',
+		],
+	},
+	only_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_schema.sql",
+			'-n', 'dump_test',
+			'postgres',
+		],
+	},
+	only_dump_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_table.sql",
+			'-t', 'dump_test.test_table',
+			'--lock-wait-timeout=1000000',
+			'postgres',
+		],
+	},
+	role => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/role.sql",
+			'--role=dump_test',
+			'--schema=dump_test_second_schema',
+			'postgres',
+		],
+	},
+	schema_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/schema_only.sql",
+			'-s',
+			'postgres',
+		],
+	},
+	section_pre_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_pre_data.sql",
+			'--section=pre-data',
+			'postgres',
+		],
+	},
+	section_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_data.sql",
+			'--section=data',
+			'postgres',
+		],
+	},
+	section_post_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_post_data.sql",
+			'--section=post-data',
+			'postgres',
+		],
+	},
+	test_schema_plus_blobs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/test_schema_plus_blobs.sql",
+			'-n', 'dump_test',
+			'-b',
+			'postgres',
+		],
+	},
+);
+
+###############################################################
+# Definition of the tests to run.
+#
+# Each test is defined using the log message that will be used.
+#
+# A regexp should be defined for each test which provides the
+# basis for the test.  That regexp will be run against the output
+# file of each of the runs which the test is to be run against
+# and the success of the result will depend on if the regexp
+# result matches the expected 'like' or 'unlike' case.
+#
+# For each test, there are two sets of runs defined, one for
+# the 'like' tests and one for the 'unlike' tests.  'like'
+# essentially means "the regexp for this test must match the
+# output file".  'unlike' is the opposite.
+#
+# There are a few 'catch-all' tests which can be used to have
+# a single, simple, test to over a range of other tests.  For
+# example, there is a '^CREATE ' test, which is used for the
+# 'data-only' test as there should never be any kind of CREATE
+# statement in a 'data-only' run.  Without the catch-all, we
+# would have to list the 'data-only' run in each and every
+# 'CREATE xxxx' test, which would be a lot of additional tests.
+#
+# Note that it makes no sense for the same run to ever be listed
+# in both 'like' and 'unlike' categories.
+#
+# There can then be a 'create_sql' and 'create_order' for a
+# given test.  The 'create_sql' commands are collected up in
+# 'create_order' and then run against the database prior to any
+# of the pg_dump runs happening.  This is what "seeds" the
+# system with objects to be dumped out.
+#
+# Building of this hash takes a bit of time as all of the regexps
+# included in it are compiled.  This greatly improves performance
+# as the regexps are used for each run the test applies to.
+
+my %tests = (
+	'ALTER DEFAULT PRIVILEGES FOR ROLE dump_test' => {
+		create_order => 14,
+		create_sql => 'ALTER DEFAULT PRIVILEGES FOR ROLE dump_test IN SCHEMA dump_test GRANT SELECT ON TABLES TO dump_test;',
+		regexp => qr/^ALTER DEFAULT PRIVILEGES FOR ROLE dump_test IN SCHEMA dump_test GRANT SELECT ON TABLES  TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			no_privs => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_pre_data => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER ROLE dump_test' => {
+		regexp => qr/^ALTER ROLE dump_test WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN NOREPLICATION NOBYPASSRLS;$/m,
+		like => {
+			pg_dumpall_globals => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER FUNCTION dump_test.pltestlang_call_handler() OWNER TO' => {
+		regexp => qr/^ALTER FUNCTION dump_test\.pltestlang_call_handler\(\) OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO' => {
+		regexp => qr/^ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER SCHEMA dump_test OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER SCHEMA dump_test_second_schema OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test_second_schema OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER TABLE ONLY test_table ADD CONSTRAINT test_table_pkey PRIMARY KEY' => {
+		regexp => qr/^ALTER TABLE ONLY test_table\n^\s+ADD CONSTRAINT test_table_pkey PRIMARY KEY \(col1\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_pre_data => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER TABLE test_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_table ENABLE ROW LEVEL SECURITY' => {
+		create_order => 23,
+		create_sql => 'ALTER TABLE dump_test.test_table ENABLE ROW LEVEL SECURITY;',
+		regexp => qr/^ALTER TABLE test_table ENABLE ROW LEVEL SECURITY;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_second_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_second_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_third_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_third_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER ... OWNER commands (except LARGE OBJECTs)' => { # catch-all for ALTER ... OWNER (except LARGE OBJECTs)
+		regexp => qr/^ALTER (?!LARGE OBJECT)(.*) OWNER TO .*;$/m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER ... OWNER commands' => { # catch-all for ALTER ... OWNER
+		regexp => qr/^ALTER .* OWNER TO .*;$/m,
+		like => { }, # use more-specific options above
+		unlike => {
+			no_owner => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'BLOB load (contents are of test_table)' => {
+		create_order => 14,
+		create_sql =>
+		    "\\o '$tempdir/large_object_test.sql'\n"
+		  . "table dump_test.test_table;\n"
+		  . "\\o\n"
+		  . "\\lo_import '$tempdir/large_object_test.sql'\n",
+		regexp => qr/^SELECT pg_catalog\.lo_open\('\d+', \d+\);\nSELECT pg_catalog\.lowrite\(0, '\\x310a320a330a340a350a360a370a380a390a\'\);\nSELECT pg_catalog\.lo_close\(0\);$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+	},
+	'COMMENT ON DATABASE postgres' => {
+		regexp => qr/^COMMENT ON DATABASE postgres IS .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT ON EXTENSION plpgsql' => {
+		regexp => qr/^COMMENT ON EXTENSION plpgsql IS .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT commands' => { # catch-all for COMMENTs
+		regexp => qr/^COMMENT ON /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			pg_dumpall_globals => 1,
+			section_data => 1,
+			section_post_data => 1,
+		},
+	},
+	'COPY test_table' => {
+		create_order => 4,
+		create_sql =>
+		    'INSERT INTO dump_test.test_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,9);',
+		regexp => qr/^COPY test_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+		},
+	},
+	'COPY fk_reference_test_table' => {
+		create_order => 22,
+		create_sql =>
+		    'INSERT INTO dump_test.fk_reference_test_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,5);',
+		regexp => qr/^COPY fk_reference_test_table \(col1\) FROM stdin;\n(?:\d\n){5}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY fk_reference_test_table second' => {
+		regexp => qr/^COPY test_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n.*COPY fk_reference_test_table \(col1\) FROM stdin;\n(?:\d\n){5}\\\.\n$/ms,
+		like => {
+			data_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+		},
+	},
+	'COPY test_second_table' => {
+		create_order => 7,
+		create_sql =>
+		    'INSERT INTO dump_test.test_second_table (col1, col2) '
+		  . 'SELECT generate_series, generate_series::text FROM generate_series(1,9);',
+		regexp => qr/^COPY test_second_table \(col1, col2\) FROM stdin;\n(?:\d\t\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY test_third_table' => {
+		create_order => 12,
+		create_sql =>
+			'INSERT INTO dump_test_second_schema.test_third_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,9);',
+		regexp => qr/^COPY test_third_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_table' => {
+		regexp => qr/^(?:INSERT INTO test_table \(col1\) VALUES \(\d\);\n){9}$/m,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_second_table' => {
+		regexp => qr/^(?:INSERT INTO test_second_table \(col1, col2\) VALUES \(\d, '\d'\);\n){9}$/m,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_third_table' => {
+		regexp => qr/^(?:INSERT INTO test_third_table \(col1\) VALUES \(\d\);\n){9}$/m,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'COPY ... commands' => { # catch-all for COPY
+		regexp => qr/^COPY /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			binary_upgrade => 1,
+			column_inserts => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE ROLE dump_test' => {
+		create_order => 1,
+		create_sql => 'CREATE ROLE dump_test;',
+		regexp => qr/^CREATE ROLE dump_test;$/m,
+		like => {
+			pg_dumpall_globals => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE DATABASE postgres' => {
+		regexp => qr/^CREATE DATABASE postgres WITH TEMPLATE = template0 .*;$/m,
+		like => {
+			createdb => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE EXTENSION ... plpgsql' => {
+		regexp => qr/^CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE AGGREGATE dump_test.newavg' => {
+		create_order => 25,
+		create_sql => 'CREATE AGGREGATE dump_test.newavg (sfunc = int4_avg_accum, basetype = int4, stype = _int8, finalfunc = int8_avg, initcond1 = \'{0,0}\');',
+		regexp => qr/^CREATE AGGREGATE newavg\(integer\) \(\n\s+SFUNC = int4_avg_accum,\n\s+STYPE = bigint\[\],\n\s+INITCOND = \'\{0,0\}\',\n\s+FINALFUNC = int8_avg\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE DOMAIN dump_test.us_postal_code' => {
+		create_order => 29,
+		create_sql => 'CREATE DOMAIN dump_test.us_postal_code AS TEXT CHECK(VALUE ~ \'^\d{5}$\' OR VALUE ~ \'^\d{5}-\d{4}$\');',
+		regexp => qr/CREATE DOMAIN us_postal_code AS text\n\s+CONSTRAINT us_postal_code_check CHECK \(\(\(VALUE ~ \'\^\\d\{5\}\$\'::text\) OR \(VALUE ~ \'\^\\d\{5\}-\\d\{4\}\$\'::text\)\)\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.pltestlang_call_handler' => {
+		create_order => 17,
+		create_sql => 'CREATE FUNCTION dump_test.pltestlang_call_handler() RETURNS LANGUAGE_HANDLER AS \'$libdir/plpgsql\', \'plpgsql_call_handler\' LANGUAGE C;',
+		regexp => qr/^CREATE FUNCTION pltestlang_call_handler\(\) RETURNS language_handler\n\s+LANGUAGE c\n\s+AS '\$libdir\/plpgsql', 'plpgsql_call_handler';$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE LANGUAGE pltestlang' => {
+		create_order => 18,
+		create_sql => 'CREATE LANGUAGE pltestlang HANDLER dump_test.pltestlang_call_handler;',
+		regexp => qr/^CREATE PROCEDURAL LANGUAGE pltestlang HANDLER pltestlang_call_handler;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE MATERIALIZED VIEW matview' => {
+		create_order => 20,
+		create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview (col1) AS SELECT * FROM dump_test.test_table;',
+		regexp => qr/^CREATE MATERIALIZED VIEW matview AS\n\s+SELECT test_table\.col1\n\s+FROM test_table\n\s+WITH NO DATA;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE MATERIALIZED VIEW matview_second' => {
+		create_order => 21,
+		create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview_second (col1) AS SELECT * FROM dump_test.matview;',
+		regexp => qr/^CREATE MATERIALIZED VIEW matview_second AS\n\s+SELECT matview\.col1\n\s+FROM matview\n\s+WITH NO DATA;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE POLICY p1 ON test_table' => {
+		create_order => 22,
+		create_sql => 'CREATE POLICY p1 ON dump_test.test_table USING (true) WITH CHECK (true);',
+		regexp => qr/^CREATE POLICY p1 ON test_table FOR ALL TO PUBLIC USING \(true\) WITH CHECK \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p2 ON test_table FOR SELECT' => {
+		create_order => 24,
+		create_sql => 'CREATE POLICY p2 ON dump_test.test_table FOR SELECT TO dump_test USING (true);',
+		regexp => qr/^CREATE POLICY p2 ON test_table FOR SELECT TO dump_test USING \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p3 ON test_table FOR INSERT' => {
+		create_order => 25,
+		create_sql => 'CREATE POLICY p3 ON dump_test.test_table FOR INSERT TO dump_test WITH CHECK (true);',
+		regexp => qr/^CREATE POLICY p3 ON test_table FOR INSERT TO dump_test WITH CHECK \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p4 ON test_table FOR UPDATE' => {
+		create_order => 26,
+		create_sql => 'CREATE POLICY p4 ON dump_test.test_table FOR UPDATE TO dump_test USING (true) WITH CHECK (true);',
+		regexp => qr/^CREATE POLICY p4 ON test_table FOR UPDATE TO dump_test USING \(true\) WITH CHECK \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p5 ON test_table FOR DELETE' => {
+		create_order => 27,
+		create_sql => 'CREATE POLICY p5 ON dump_test.test_table FOR DELETE TO dump_test USING (true);',
+		regexp => qr/^CREATE POLICY p5 ON test_table FOR DELETE TO dump_test USING \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test' => {
+		create_order => 2,
+		create_sql => 'CREATE SCHEMA dump_test;',
+		regexp => qr/^CREATE SCHEMA dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test_second_schema' => {
+		create_order => 9,
+		create_sql => 'CREATE SCHEMA dump_test_second_schema;',
+		regexp => qr/^CREATE SCHEMA dump_test_second_schema;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE TABLE test_table' => {
+		create_order => 3,
+		create_sql => 'CREATE TABLE dump_test.test_table (col1 serial primary key);',
+		regexp => qr/^CREATE TABLE test_table \(\n\s+col1 integer NOT NULL\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE fk_reference_test_table' => {
+		create_order => 21,
+		create_sql => 'CREATE TABLE dump_test.fk_reference_test_table (col1 int primary key references dump_test.test_table);',
+		regexp => qr/^CREATE TABLE fk_reference_test_table \(\n\s+col1 integer NOT NULL\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE test_second_table' => {
+		create_order => 6,
+		create_sql => 'CREATE TABLE dump_test.test_second_table (col1 int, col2 text);',
+		regexp => qr/^CREATE TABLE test_second_table \(\n\s+col1 integer,\n\s+col2 text\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE test_third_table' => {
+		create_order => 11,
+		create_sql => 'CREATE TABLE dump_test_second_schema.test_third_table (col1 serial);',
+		regexp => qr/^CREATE TABLE test_third_table \(\n\s+col1 integer NOT NULL\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE SEQUENCE test_table_col1_seq' => {
+		regexp => qr/^CREATE SEQUENCE test_table_col1_seq\n\s+START WITH 1\n\s+INCREMENT BY 1\n\s+NO MINVALUE\n\s+NO MAXVALUE\n\s+CACHE 1;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE SEQUENCE test_third_table_col1_seq' => {
+		regexp => qr/^CREATE SEQUENCE test_third_table_col1_seq\n\s+START WITH 1\n\s+INCREMENT BY 1\n\s+NO MINVALUE\n\s+NO MAXVALUE\n\s+CACHE 1;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE UNIQUE INDEX test_third_table_idx ON test_third_table' => {
+		create_order => 13,
+		create_sql => 'CREATE UNIQUE INDEX test_third_table_idx ON dump_test_second_schema.test_third_table (col1);',
+		regexp => qr/^CREATE UNIQUE INDEX test_third_table_idx ON test_third_table USING btree \(col1\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE ... commands' => { # catch-all for CREATE
+		regexp => qr/^CREATE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			section_data => 1,
+		},
+	},
+	'DROP EXTENSION plpgsql' => {
+		regexp => qr/^DROP EXTENSION plpgsql;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP FUNCTION dump_test.pltestlang_call_handler()' => {
+		regexp => qr/^DROP FUNCTION dump_test\.pltestlang_call_handler\(\);$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP LANGUAGE pltestlang' => {
+		regexp => qr/^DROP PROCEDURAL LANGUAGE pltestlang;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test' => {
+		regexp => qr/^DROP SCHEMA dump_test;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA dump_test_second_schema;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE fk_reference_test_table' => {
+		regexp => qr/^DROP TABLE dump_test\.fk_reference_test_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_second_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_second_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_third_table' => {
+		regexp => qr/^DROP TABLE dump_test_second_schema\.test_third_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP EXTENSION IF EXISTS plpgsql' => {
+		regexp => qr/^DROP EXTENSION IF EXISTS plpgsql;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler()' => {
+		regexp => qr/^DROP FUNCTION IF EXISTS dump_test\.pltestlang_call_handler\(\);$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP LANGUAGE IF EXISTS pltestlang' => {
+		regexp => qr/^DROP PROCEDURAL LANGUAGE IF EXISTS pltestlang;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test_second_schema;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_second_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_second_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_third_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test_second_schema\.test_third_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP ... commands' => { # catch-all for DROP
+		regexp => qr/^DROP /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			binary_upgrade => 1,
+			column_inserts => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+		},
+	},
+	'GRANT USAGE ON SCHEMA dump_test_second_schema' => {
+		create_order => 10,
+		create_sql => 'GRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;',
+		regexp => qr/^GRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT SELECT ON TABLE test_table' => {
+		create_order => 5,
+		create_sql => 'GRANT SELECT ON TABLE dump_test.test_table TO dump_test;',
+		regexp => qr/^GRANT SELECT ON TABLE test_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'GRANT SELECT ON TABLE test_third_table' => {
+		create_order => 19,
+		create_sql => 'GRANT SELECT ON TABLE dump_test_second_schema.test_third_table TO dump_test;',
+		regexp => qr/^GRANT SELECT ON TABLE test_third_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT ALL ON SEQUENCE test_third_table_col1_seq' => {
+		create_order => 28,
+		create_sql => 'GRANT ALL ON SEQUENCE dump_test_second_schema.test_third_table_col1_seq TO dump_test;',
+		regexp => qr/^GRANT ALL ON SEQUENCE test_third_table_col1_seq TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT INSERT(col1) ON TABLE test_second_table' => {
+		create_order => 8,
+		create_sql => 'GRANT INSERT (col1) ON TABLE dump_test.test_second_table TO dump_test;',
+		regexp => qr/^GRANT INSERT\(col1\) ON TABLE test_second_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'GRANT EXECUTE ON FUNCTION pg_sleep() TO dump_test' => {
+		create_order => 16,
+		create_sql => 'GRANT EXECUTE ON FUNCTION pg_sleep(float8) TO dump_test;',
+		regexp => qr/^GRANT ALL ON FUNCTION pg_sleep\(double precision\) TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT commands' => { # catch-all for GRANT commands
+		regexp => qr/^GRANT /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			no_privs => 1,
+			section_data => 1,
+		},
+	},
+	'REFRESH MATERIALIZED VIEW matview' => {
+		regexp => qr/^REFRESH MATERIALIZED VIEW matview;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+	},
+	'REFRESH MATERIALIZED VIEW matview_second' => {
+		regexp => qr/^REFRESH MATERIALIZED VIEW matview;\n.*REFRESH MATERIALIZED VIEW matview_second;$/ms,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+	},
+	'REVOKE EXECUTE ON FUNCTION pg_sleep() FROM public' => {
+		create_order => 15,
+		create_sql => 'REVOKE EXECUTE ON FUNCTION pg_sleep(float8) FROM public;',
+		regexp => qr/^REVOKE ALL ON FUNCTION pg_sleep\(double precision\) FROM PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE CREATE ON SCHEMA public FROM public' => {
+		create_order => 16,
+		create_sql => 'REVOKE CREATE ON SCHEMA public FROM public;',
+		regexp => qr/^REVOKE ALL ON SCHEMA public FROM PUBLIC;\nGRANT USAGE ON SCHEMA public TO PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE USAGE ON LANGUAGE plpgsql FROM public' => {
+		create_order => 16,
+		create_sql => 'REVOKE USAGE ON LANGUAGE plpgsql FROM public;',
+		regexp => qr/^REVOKE ALL ON LANGUAGE plpgsql FROM PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE commands' => { # catch-all for REVOKE commands
+		regexp => qr/^REVOKE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			no_privs => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+);
+
+#########################################
+# Create a PG instance to test actually dumping from
+
+my $node = get_new_node('main');
+$node->init;
+$node->start;
+
+my $port = $node->port;
+
+# Start with 2 because of command_exit_is() tests below
+my $num_tests = 2;
+
+foreach my $run (sort keys %pgdump_runs) {
+	my $test_key = $run;
+
+	# Each run of pg_dump is a test itself
+	$num_tests++;
+
+	# If there is a restore cmd, that's another test
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$num_tests++;
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	# Then count all the tests run against each run
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			$num_tests++;
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			$num_tests++;
+		}
+	}
+}
+plan tests => $num_tests;
+
+#########################################
+# Set up schemas, tables, etc, to be dumped.
+
+# Build up the create statements
+my $create_sql = '';
+
+foreach my $test (
+	sort {
+		if ($tests{$a}->{create_order} and $tests{$b}->{create_order}) {
+			$tests{$a}->{create_order} <=> $tests{$b}->{create_order};
+		} elsif ($tests{$a}->{create_order}) {
+			-1;
+		} elsif ($tests{$b}->{create_order}) {
+			1;
+		} else {
+			0;
+		}
+	} keys %tests) {
+	if ($tests{$test}->{create_sql}) {
+		$create_sql .= $tests{$test}->{create_sql};
+	}
+}
+
+# Send the combined set of commands to psql
+$node->safe_psql('postgres', $create_sql);
+
+#########################################
+# Test connecting to a non-existent database
+
+command_exit_is([ 'pg_dump', '-p', "$port", 'qqq' ],
+	1, 'pg_dump: [archiver (db)] connection to database "qqq" failed: FATAL:  database "qqq" does not exist');
+
+command_exit_is([ 'pg_dump', '-p', "$port", '--role=dump_test' ],
+	1, 'pg_dump: [archiver (db)] query failed: ERROR:  permission denied for');
+
+#########################################
+# Run all runs
+
+foreach my $run (sort keys %pgdump_runs) {
+
+	my $test_key = $run;
+
+	$node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs");
+
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$node->command_ok(\@{ $pgdump_runs{$run}->{restore_cmd} }, "$run: pg_restore runs");
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	my $output_file = slurp_file("$tempdir/${run}.sql");
+
+	#########################################
+	# Run all tests where this run is included
+	# as either a 'like' or 'unlike' test.
+
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			like($output_file, $tests{$test}->{regexp}, "$run: dumps $test");
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			unlike($output_file, $tests{$test}->{regexp}, "$run: does not dump $test");
+		}
+	}
+}
+
+#########################################
+# Stop the database instance, which will be removed at the end of the tests.
+
+$node->stop('fast');
-- 
2.5.0

#28Stephen Frost
sfrost@snowman.net
In reply to: Stephen Frost (#27)
1 attachment(s)

Noah, all,

* Stephen Frost (sfrost@snowman.net) wrote:

The test suite is now covering 57% of pg_dump.c. I was hoping to get
that number higher, but time marches on and more tests can certainly be
added later.

I've managed to get the test suite up another 10%, to 67% of pg_dump.c.
Still quite a bit to do, but it turned up a bug in CREATE TRANSFORM,
which lead to Peter discovering a similar issue in CREATE CAST, so I'd
say it's certainly showing that it's worthwhile to have.

Updated patch-set which includes the additional tests and also a patch
to avoid LOCK'ing tables when we don't need to, as discussed with Tom
and Robert on another thread.

Thanks!

Stephen

Attachments:

pg_dump_improvements_v3.patchtext/x-diff; charset=us-asciiDownload
From cea33c3fdbdfa4ff27c0ff6ed7b708705dfa17fe Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 24 Apr 2016 23:59:23 -0400
Subject: [PATCH 1/4] Correct pg_dump WHERE clause for functions/aggregates

The query to grab the function/aggregate information is now joining
to pg_init_privs, so we can simplify (and correct) the WHERE clause
used to determine if a given function's ACL has changed from the
initial ACL on the function.

Bug found by Noah, patch by me.
---
 src/bin/pg_dump/pg_dump.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d3f5157..bb33075 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -4673,11 +4673,7 @@ getAggregates(Archive *fout, int *numAggs)
 						  "p.pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  username_subquery,
 						  acl_subquery->data,
 						  racl_subquery->data,
@@ -4923,11 +4919,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  acl_subquery->data,
 						  racl_subquery->data,
 						  initacl_subquery->data,
-- 
2.5.0


From 707707ba1c2ee601ce893258eaaf5c54341806f6 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:00:15 -0400
Subject: [PATCH 2/4] pg_dump performance and other fixes

Do not try to dump objects which do not have ACLs when only ACLs are
being requested.  This results in a significant performance improvement
as we can avoid querying for further information on these objects when
we don't need to.

When limiting the components to dump for an extension, consider what
components have been requested.  Initially, we incorrectly hard-coded
the components of the extension objects to dump, which would mean that
we wouldn't dump some components even with they were asked for and in
other cases we would dump components which weren't requested.

Correct defaultACLs to use 'dump_contains' instead of 'dump'.  The
defaultACL is considered a member of the namespace and should be
dumped based on the same set of components that the other objects in
the schema are, not based on what we're dumping for the namespace
itself (which might not include ACLs, if the namespace has just the
default or initial ACL).

Use DUMP_COMPONENT_ACL for from-initdb objects, to allow users to
change their ACLs, should they wish to.  This just extends what we
are doing for the pg_catalog namespace to objects which are not
members of namespaces.
---
 src/bin/pg_dump/pg_dump.c | 176 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 149 insertions(+), 27 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index bb33075..d826b4d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1297,14 +1297,17 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout)
 	 * contents rather than replace the extension contents with something
 	 * different.
 	 */
-	if (!fout->dopt->binary_upgrade && fout->remoteVersion >= 90600)
-		dobj->dump = DUMP_COMPONENT_ACL |
-			DUMP_COMPONENT_SECLABEL |
-			DUMP_COMPONENT_POLICY;
-	else if (!fout->dopt->binary_upgrade)
-		dobj->dump = DUMP_COMPONENT_NONE;
-	else
+	if (fout->dopt->binary_upgrade)
 		dobj->dump = ext->dobj.dump;
+	else
+	{
+		if (fout->remoteVersion < 90600)
+			dobj->dump = DUMP_COMPONENT_NONE;
+		else
+			dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
+					DUMP_COMPONENT_SECLABEL | DUMP_COMPONENT_POLICY);
+
+	}
 
 	return true;
 }
@@ -1452,7 +1455,7 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 
 	if (dinfo->dobj.namespace)
 		/* default ACLs are considered part of the namespace */
-		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
+		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
 	else
 		dinfo->dobj.dump = dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
@@ -1473,6 +1476,10 @@ selectDumpableCast(CastInfo *cast, Archive *fout)
 	if (checkExtensionMembership(&cast->dobj, fout))
 		return;					/* extension membership overrides all else */
 
+	/*
+	 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
+	 * support ACLs currently.
+	 */
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
@@ -1494,11 +1501,23 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
 	if (checkExtensionMembership(&plang->dobj, fout))
 		return;					/* extension membership overrides all else */
 
-	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
+	/*
+	 * Only include procedural languages when we are dumping everything.
+	 *
+	 * For from-initdb procedural languages, only include ACLs, as we do for
+	 * the pg_catalog namespace.  We need this because procedural languages do
+	 * not live in any namespace.
+	 */
+	if (!fout->dopt->include_everything)
 		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = fout->dopt->include_everything ?
-			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+	{
+		if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
+			plang->dobj.dump = fout->remoteVersion < 90600 ?
+				DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
+		else
+			plang->dobj.dump = DUMP_COMPONENT_ALL;
+	}
 }
 
 /*
@@ -1515,6 +1534,10 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 	if (checkExtensionMembership(&method->dobj, fout))
 		return;					/* extension membership overrides all else */
 
+	/*
+	 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
+	 * they do not support ACLs currently.
+	 */
 	if (method->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		method->dobj.dump = DUMP_COMPONENT_NONE;
 	else
@@ -1535,11 +1558,17 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 static void
 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 {
+	/*
+	 * Use DUMP_COMPONENT_ACL for from-initdb extensions, to allow users
+	 * to change permissions on those objects, if they wish to, and have
+	 * those changes preserved.
+	 */
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		extinfo->dobj.dump = DUMP_COMPONENT_ACL;
 	else
-		extinfo->dobj.dump = dopt->include_everything ?
-			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+		extinfo->dobj.dump = extinfo->dobj.dump_contains =
+			dopt->include_everything ?  DUMP_COMPONENT_ALL :
+				DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -4175,6 +4204,9 @@ getOperators(Archive *fout, int *numOprs)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(oprinfo[i].dobj), fout);
 
+		/* Operators do not currently have ACLs. */
+		oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (strlen(oprinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
 					  oprinfo[i].dobj.name);
@@ -4259,6 +4291,9 @@ getCollations(Archive *fout, int *numCollations)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(collinfo[i].dobj), fout);
+
+		/* Collations do not currently have ACLs. */
+		collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4340,6 +4375,9 @@ getConversions(Archive *fout, int *numConversions)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(convinfo[i].dobj), fout);
+
+		/* Conversions do not currently have ACLs. */
+		convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4413,6 +4451,9 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 
 		/* Decide whether we want to dump it */
 		selectDumpableAccessMethod(&(aminfo[i]), fout);
+
+		/* Access methods do not currently have ACLs. */
+		aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4506,6 +4547,9 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opcinfo[i].dobj), fout);
 
+		/* Op Classes do not currently have ACLs. */
+		opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opcinfo[i].rolname) == 0)
@@ -4594,6 +4638,9 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opfinfo[i].dobj), fout);
 
+		/* Extensions do not currently have ACLs. */
+		opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opfinfo[i].rolname) == 0)
@@ -5123,6 +5170,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_toastreloptions;
 	int			i_reloftype;
 	int			i_relpages;
+	int			i_changed_acl;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
@@ -5154,6 +5202,11 @@ getTables(Archive *fout, int *numTables)
 		PQExpBuffer initacl_subquery = createPQExpBuffer();
 		PQExpBuffer initracl_subquery = createPQExpBuffer();
 
+		PQExpBuffer attacl_subquery = createPQExpBuffer();
+		PQExpBuffer attracl_subquery = createPQExpBuffer();
+		PQExpBuffer attinitacl_subquery = createPQExpBuffer();
+		PQExpBuffer attinitracl_subquery = createPQExpBuffer();
+
 		/*
 		 * Left join to pick up dependency info linking sequences to their
 		 * owning column, if any (note this dependency is AUTO as of 8.2)
@@ -5167,6 +5220,10 @@ getTables(Archive *fout, int *numTables)
 				 "CASE WHEN c.relkind = 'S' THEN 's' ELSE 'r' END::\"char\"",
 						dopt->binary_upgrade);
 
+		buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
+						attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
+						dopt->binary_upgrade);
+
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
 						  "%s AS relacl, %s as rrelacl, "
@@ -5188,7 +5245,17 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON"
+						  "(c.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND pip.objsubid = at.attnum)"
+						  "WHERE at.attrelid = c.oid AND ("
+						  "%s IS NOT NULL "
+						  "OR %s IS NOT NULL "
+						  "OR %s IS NOT NULL "
+						  "OR %s IS NOT NULL"
+						  "))"
+						  "AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5207,6 +5274,10 @@ getTables(Archive *fout, int *numTables)
 						  initacl_subquery->data,
 						  initracl_subquery->data,
 						  username_subquery,
+						  attacl_subquery->data,
+						  attracl_subquery->data,
+						  attinitacl_subquery->data,
+						  attinitracl_subquery->data,
 						  RELKIND_SEQUENCE,
 						  RELKIND_RELATION, RELKIND_SEQUENCE,
 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
@@ -5216,6 +5287,11 @@ getTables(Archive *fout, int *numTables)
 		destroyPQExpBuffer(racl_subquery);
 		destroyPQExpBuffer(initacl_subquery);
 		destroyPQExpBuffer(initracl_subquery);
+
+		destroyPQExpBuffer(attacl_subquery);
+		destroyPQExpBuffer(attracl_subquery);
+		destroyPQExpBuffer(attinitacl_subquery);
+		destroyPQExpBuffer(attinitracl_subquery);
 	}
 	else if (fout->remoteVersion >= 90500)
 	{
@@ -5245,7 +5321,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5290,7 +5367,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5335,7 +5413,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5378,7 +5457,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5421,7 +5501,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5463,7 +5544,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5505,7 +5587,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5546,7 +5629,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5586,7 +5670,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5623,7 +5708,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5655,7 +5741,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5695,7 +5782,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "WHERE relkind IN ('%c', '%c') "
 						  "ORDER BY oid",
@@ -5754,6 +5842,7 @@ getTables(Archive *fout, int *numTables)
 	i_checkoption = PQfnumber(res, "checkoption");
 	i_toastreloptions = PQfnumber(res, "toast_reloptions");
 	i_reloftype = PQfnumber(res, "reloftype");
+	i_changed_acl = PQfnumber(res, "changed_acl");
 
 	if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
 	{
@@ -5835,6 +5924,21 @@ getTables(Archive *fout, int *numTables)
 		else
 			selectDumpableTable(&tblinfo[i], fout);
 
+		/*
+		 * If the table-level and all column-level ACLs for this table are
+		 * unchanged, then we don't need to worry about including the ACLs
+		 * for this table.  If any column-level ACLs have been changed, the
+		 * 'changed_acl' column from the query will indicate that.
+		 *
+		 * This can result in a significant performance improvement in cases
+		 * where we are only looking to dump out the ACL (eg: pg_catalog).
+		 */
+		if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
+			PQgetisnull(res, i, i_initrelacl) &&
+			PQgetisnull(res, i, i_initrrelacl) &&
+			strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
+			tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
@@ -6989,6 +7093,9 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(evtinfo[i].dobj), fout);
+
+		/* Event Triggers do not currently have ACLs. */
+		evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -7350,6 +7457,9 @@ getCasts(Archive *fout, int *numCasts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableCast(&(castinfo[i]), fout);
+
+		/* Casts do not currently have ACLs. */
+		castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8143,6 +8253,9 @@ getTSParsers(Archive *fout, int *numTSParsers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(prsinfo[i].dobj), fout);
+
+		/* Text Search Parsers do not currently have ACLs. */
+		prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8228,6 +8341,9 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(dictinfo[i].dobj), fout);
+
+		/* Text Search Dictionaries do not currently have ACLs. */
+		dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8305,6 +8421,9 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(tmplinfo[i].dobj), fout);
+
+		/* Text Search Templates do not currently have ACLs. */
+		tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8383,6 +8502,9 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(cfginfo[i].dobj), fout);
+
+		/* Text Search Configurations do not currently have ACLs. */
+		cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
-- 
2.5.0


From 32645eac291b546df2acb23685c0a5f123131efa Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Wed, 4 May 2016 13:40:36 -0400
Subject: [PATCH 3/4] Only issue LOCK TABLE commands when necessary

Reviewing the cases where we need to LOCK a given table during a dump,
it was pointed out by Tom that we really don't need to LOCK a table if
we are only looking to dump the ACL for it, or certain other
components.  After reviewing the queries run for all of the component
pieces, a list of components were determined to not require LOCK'ing
of the table.

This implements a check to avoid LOCK'ing those tables.

Initial complaint from Rushabh Lathia, discussed with Robert and Tom,
the patch is mine.
---
 src/bin/pg_dump/pg_dump.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d826b4d..2c75b70 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -5947,14 +5947,37 @@ getTables(Archive *fout, int *numTables)
 		 * Read-lock target tables to make sure they aren't DROPPED or altered
 		 * in schema before we get around to dumping them.
 		 *
+		 * Note that some components only require looking at the information
+		 * in the pg_catalog tables and, for those components, we do not need
+		 * to lock the table.  Be careful here though- some components use
+		 * server-side functions which pull the latest information from
+		 * SysCache and in those cases we *do* need to lock the table.
+		 *
 		 * Note that we don't explicitly lock parents of the target tables; we
 		 * assume our lock on the child is enough to prevent schema
 		 * alterations to parent tables.
 		 *
 		 * NOTE: it'd be kinda nice to lock other relations too, not only
 		 * plain tables, but the backend doesn't presently allow that.
+		 *
+		 * We do not need locks for the COMMENT and SECLABEL components as
+		 * those simply query their associated tables without using any
+		 * server-side functions.  We do not need locks for the ACL component
+		 * as we pull that information from pg_class without using any
+		 * server-side functions that use SysCache.  The USERMAP component
+		 * is only relevant for FOREIGN SERVERs and not tables, so no sense
+		 * locking a table for that either (that can happen if we are going
+		 * to dump "ALL" components for a table).
+		 *
+		 * We DO need locks for DEFINITION, due to various server-side
+		 * functions that are used and POLICY due to pg_get_expr().  We set
+		 * this up to grab the lock except in the cases we know to be safe.
 		 */
-		if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
+		if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION &&
+				(tblinfo[i].dobj.dump & ~(DUMP_COMPONENT_COMMENT |
+										  DUMP_COMPONENT_SECLABEL |
+										  DUMP_COMPONENT_ACL |
+										  DUMP_COMPONENT_USERMAP)))
 		{
 			resetPQExpBuffer(query);
 			appendPQExpBuffer(query,
-- 
2.5.0


From 2da8870c61431d6ec4586b350ec56a8a947afe8a Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:01:38 -0400
Subject: [PATCH 4/4] Add TAP tests for pg_dump

This TAP test suite will create a new cluster, populate it based on
the 'create_sql' values in the '%tests' hash, run all of the runs
defined in the '%pgdump_runs' hash, and then for each test in the
'%tests' hash, compare each run's output the the regular expression
defined for the test under the 'like' and 'unlike' functions, as
appropriate.

While this test suite covers a fair bit of ground (67% of pg_dump.c
and quite a bit of the other files in src/bin/pg_dump), there is
still quite a bit which remains to be added to provide better code
coverage.  Still, this is quite a bit better than we had, and has
found a few bugs already (note that the CREATE TRANSFORM test is
commented out, as it is currently failing).

Idea for using the TAP system from Tom, though all of the code is mine.
---
 src/bin/pg_dump/Makefile         |    3 +
 src/bin/pg_dump/pg_dump.c        |    2 +-
 src/bin/pg_dump/t/001_basic.pl   |   42 +
 src/bin/pg_dump/t/002_pg_dump.pl | 2466 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 2512 insertions(+), 1 deletion(-)
 create mode 100644 src/bin/pg_dump/t/001_basic.pl
 create mode 100644 src/bin/pg_dump/t/002_pg_dump.pl

diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index 9596789..260804b 100644
--- a/src/bin/pg_dump/Makefile
+++ b/src/bin/pg_dump/Makefile
@@ -42,6 +42,9 @@ install: all installdirs
 installdirs:
 	$(MKDIR_P) '$(DESTDIR)$(bindir)'
 
+check:
+	$(prove_check)
+
 uninstall:
 	rm -f $(addprefix '$(DESTDIR)$(bindir)'/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X))
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2c75b70..7cd62ca 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1564,7 +1564,7 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 	 * those changes preserved.
 	 */
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = DUMP_COMPONENT_ACL;
+		extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
 	else
 		extinfo->dobj.dump = extinfo->dobj.dump_contains =
 			dopt->include_everything ?  DUMP_COMPONENT_ALL :
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
new file mode 100644
index 0000000..1411ef7
--- /dev/null
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -0,0 +1,42 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More tests => 15;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+#########################################
+# Basic checks
+
+program_help_ok('pg_dump');
+program_version_ok('pg_dump');
+program_options_handling_ok('pg_dump');
+
+#########################################
+# Test various invalid options and disallowed combinations
+# Doesn't require a PG instance to be set up, so do this first.
+
+command_exit_is([ 'pg_dump', 'qqq', 'abc' ],
+	1, 'pg_dump: too many command-line arguments (first is "asd")');
+
+command_exit_is([ 'pg_dump', '-s', '-a' ],
+	1, 'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '-c', '-a' ],
+	1, 'pg_dump: options -c/--clean and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '--inserts', '-o' ],
+	1, 'pg_dump: options --inserts/--column-inserts and -o/--oids cannot be used together');
+
+command_exit_is([ 'pg_dump', '--if-exists' ],
+	1, 'pg_dump: option --if-exists requires option -c/--clean');
+
+command_exit_is([ 'pg_dump', '-j' ],
+	1, 'pg_dump: option requires an argument -- \'j\'');
+
+command_exit_is([ 'pg_dump', '-j3' ],
+	1, 'pg_dump: parallel backup only supported by the directory format');
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
new file mode 100644
index 0000000..0d072b3
--- /dev/null
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -0,0 +1,2466 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+###############################################################
+# Definition of the pg_dump runs to make.
+#
+# Each of these runs are named and those names are used below
+# to define how each test should (or shouldn't) treat a result
+# from a given run.
+#
+# test_key indicates that a given run should simply use the same
+# set of like/unlike tests as another run, and which run that is.
+#
+# dump_cmd is the pg_dump command to run, which is an array of
+# the full command and arguments to run.  Note that this is run
+# using $node->command_ok(), so the port does not need to be
+# specified and is pulled from $PGPORT, which is set by the
+# PostgresNode system.
+#
+# restore_cmd is the pg_restore command to run, if any.  Note
+# that this should generally be used when the pg_dump goes to
+# a non-text file and that the restore can then be used to
+# generate a text file to run through the tests from the
+# non-text file generated by pg_dump.
+#
+# TODO: Have pg_restore actually restore to an independent
+# database and then pg_dump *that* database (or something along
+# those lines) to validate that part of the process.
+
+my %pgdump_runs = (
+	binary_upgrade => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/binary_upgrade.sql",
+			'--schema-only',
+			'--binary-upgrade',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean.sql",
+			'-c',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean_if_exists => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean_if_exists.sql",
+			'-c',
+			'--if-exists',
+			'-E', 'UTF8', # no-op, just tests that option is accepted
+			'postgres',
+		],
+	},
+	column_inserts => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/column_inserts.sql",
+			'-a',
+			'--column-inserts',
+			'postgres',
+		],
+	},
+	createdb => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/createdb.sql",
+			'-C',
+			'-R', # no-op, just for testing
+			'postgres',
+		],
+	},
+	data_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/data_only.sql",
+			'-a',
+			'-v', # no-op, just make sure it works
+			'postgres',
+		],
+	},
+	defaults => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/defaults.sql",
+			'postgres',
+		],
+	},
+	defaults_custom_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fc',
+			'-Z6',
+			'-f', "$tempdir/defaults_custom_format.dump",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_custom_format.sql",
+			"$tempdir/defaults_custom_format.dump",
+		],
+	},
+	defaults_dir_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-f', "$tempdir/defaults_dir_format",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_dir_format.sql",
+			"$tempdir/defaults_dir_format",
+		],
+	},
+	defaults_parallel => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-j2',
+			'-f', "$tempdir/defaults_parallel",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_parallel.sql",
+			"$tempdir/defaults_parallel",
+		],
+	},
+	defaults_tar_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Ft',
+			'-f', "$tempdir/defaults_tar_format.tar",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_tar_format.sql",
+			"$tempdir/defaults_tar_format.tar",
+		],
+	},
+	exclude_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_dump_test_schema.sql",
+			'-N', 'dump_test',
+			'postgres',
+		],
+	},
+	exclude_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table.sql",
+			'-T', 'dump_test.test_table',
+			'postgres',
+		],
+	},
+	exclude_test_table_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table_data.sql",
+			'--exclude-table-data=dump_test.test_table',
+			'postgres',
+		],
+	},
+	pg_dumpall_globals => {
+		dump_cmd => [
+			'pg_dumpall',
+			'-f', "$tempdir/pg_dumpall_globals.sql",
+			'-g',
+		],
+	},
+	no_privs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_privs.sql",
+			'-x',
+			'postgres',
+		],
+	},
+	no_owner => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_owner.sql",
+			'-O',
+			'postgres',
+		],
+	},
+	only_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_schema.sql",
+			'-n', 'dump_test',
+			'postgres',
+		],
+	},
+	only_dump_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_table.sql",
+			'-t', 'dump_test.test_table',
+			'--lock-wait-timeout=1000000',
+			'postgres',
+		],
+	},
+	role => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/role.sql",
+			'--role=dump_test',
+			'--schema=dump_test_second_schema',
+			'postgres',
+		],
+	},
+	schema_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/schema_only.sql",
+			'-s',
+			'postgres',
+		],
+	},
+	section_pre_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_pre_data.sql",
+			'--section=pre-data',
+			'postgres',
+		],
+	},
+	section_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_data.sql",
+			'--section=data',
+			'postgres',
+		],
+	},
+	section_post_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_post_data.sql",
+			'--section=post-data',
+			'postgres',
+		],
+	},
+	test_schema_plus_blobs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/test_schema_plus_blobs.sql",
+			'-n', 'dump_test',
+			'-b',
+			'postgres',
+		],
+	},
+);
+
+###############################################################
+# Definition of the tests to run.
+#
+# Each test is defined using the log message that will be used.
+#
+# A regexp should be defined for each test which provides the
+# basis for the test.  That regexp will be run against the output
+# file of each of the runs which the test is to be run against
+# and the success of the result will depend on if the regexp
+# result matches the expected 'like' or 'unlike' case.
+#
+# For each test, there are two sets of runs defined, one for
+# the 'like' tests and one for the 'unlike' tests.  'like'
+# essentially means "the regexp for this test must match the
+# output file".  'unlike' is the opposite.
+#
+# There are a few 'catch-all' tests which can be used to have
+# a single, simple, test to over a range of other tests.  For
+# example, there is a '^CREATE ' test, which is used for the
+# 'data-only' test as there should never be any kind of CREATE
+# statement in a 'data-only' run.  Without the catch-all, we
+# would have to list the 'data-only' run in each and every
+# 'CREATE xxxx' test, which would be a lot of additional tests.
+#
+# Note that it makes no sense for the same run to ever be listed
+# in both 'like' and 'unlike' categories.
+#
+# There can then be a 'create_sql' and 'create_order' for a
+# given test.  The 'create_sql' commands are collected up in
+# 'create_order' and then run against the database prior to any
+# of the pg_dump runs happening.  This is what "seeds" the
+# system with objects to be dumped out.
+#
+# Building of this hash takes a bit of time as all of the regexps
+# included in it are compiled.  This greatly improves performance
+# as the regexps are used for each run the test applies to.
+
+my %tests = (
+	'ALTER DEFAULT PRIVILEGES FOR ROLE dump_test' => {
+		create_order => 14,
+		create_sql => 'ALTER DEFAULT PRIVILEGES FOR ROLE dump_test IN SCHEMA dump_test GRANT SELECT ON TABLES TO dump_test;',
+		regexp => qr/^ALTER DEFAULT PRIVILEGES FOR ROLE dump_test IN SCHEMA dump_test GRANT SELECT ON TABLES  TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			no_privs => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_pre_data => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER ROLE dump_test' => {
+		regexp => qr/^ALTER ROLE dump_test WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN NOREPLICATION NOBYPASSRLS;$/m,
+		like => {
+			pg_dumpall_globals => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER FUNCTION dump_test.pltestlang_call_handler() OWNER TO' => {
+		regexp => qr/^ALTER FUNCTION dump_test\.pltestlang_call_handler\(\) OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO' => {
+		regexp => qr/^ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER SCHEMA dump_test OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER SCHEMA dump_test_second_schema OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test_second_schema OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER TABLE ONLY test_table ADD CONSTRAINT test_table_pkey PRIMARY KEY' => {
+		regexp => qr/^ALTER TABLE ONLY test_table\n^\s+ADD CONSTRAINT test_table_pkey PRIMARY KEY \(col1\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_pre_data => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER TABLE test_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_table ENABLE ROW LEVEL SECURITY' => {
+		create_order => 23,
+		create_sql => 'ALTER TABLE dump_test.test_table ENABLE ROW LEVEL SECURITY;',
+		regexp => qr/^ALTER TABLE test_table ENABLE ROW LEVEL SECURITY;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_second_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_second_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_third_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_third_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER ... OWNER commands (except LARGE OBJECTs)' => { # catch-all for ALTER ... OWNER (except LARGE OBJECTs)
+		regexp => qr/^ALTER (?!LARGE OBJECT)(.*) OWNER TO .*;$/m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER ... OWNER commands' => { # catch-all for ALTER ... OWNER
+		regexp => qr/^ALTER .* OWNER TO .*;$/m,
+		like => { }, # use more-specific options above
+		unlike => {
+			no_owner => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'BLOB load (contents are of test_table)' => {
+		create_order => 14,
+		create_sql =>
+		    "\\o '$tempdir/large_object_test.sql'\n"
+		  . "table dump_test.test_table;\n"
+		  . "\\o\n"
+		  . "\\lo_import '$tempdir/large_object_test.sql'\n",
+		regexp => qr/^SELECT pg_catalog\.lo_open\('\d+', \d+\);\nSELECT pg_catalog\.lowrite\(0, '\\x310a320a330a340a350a360a370a380a390a\'\);\nSELECT pg_catalog\.lo_close\(0\);$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+	},
+	'COMMENT ON DATABASE postgres' => {
+		regexp => qr/^COMMENT ON DATABASE postgres IS .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT ON EXTENSION plpgsql' => {
+		regexp => qr/^COMMENT ON EXTENSION plpgsql IS .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT ON TABLE dump_test.test_table' => {
+		create_order => 36,
+		create_sql => 'COMMENT ON TABLE dump_test.test_table IS \'comment on table\';',
+		regexp => qr/^COMMENT ON TABLE test_table IS 'comment on table';$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'COMMENT ON COLUMN dump_test.test_table.col1' => {
+		create_order => 36,
+		create_sql => 'COMMENT ON COLUMN dump_test.test_table.col1 IS \'comment on column\';',
+		regexp => qr/^COMMENT ON COLUMN test_table\.col1 IS 'comment on column';$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'COMMENT ON COLUMN dump_test.composite.f1' => {
+		create_order => 44,
+		create_sql => 'COMMENT ON COLUMN dump_test.composite.f1 IS \'comment on column of type\';',
+		regexp => qr/^COMMENT ON COLUMN composite\.f1 IS 'comment on column of type';$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT commands' => { # catch-all for COMMENTs
+		regexp => qr/^COMMENT ON /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			pg_dumpall_globals => 1,
+			section_data => 1,
+			section_post_data => 1,
+		},
+	},
+	'COPY test_table' => {
+		create_order => 4,
+		create_sql =>
+		    'INSERT INTO dump_test.test_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,9);',
+		regexp => qr/^COPY test_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+		},
+	},
+	'COPY fk_reference_test_table' => {
+		create_order => 22,
+		create_sql =>
+		    'INSERT INTO dump_test.fk_reference_test_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,5);',
+		regexp => qr/^COPY fk_reference_test_table \(col1\) FROM stdin;\n(?:\d\n){5}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY fk_reference_test_table second' => {
+		regexp => qr/^COPY test_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n.*COPY fk_reference_test_table \(col1\) FROM stdin;\n(?:\d\n){5}\\\.\n$/ms,
+		like => {
+			data_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+		},
+	},
+	'COPY test_second_table' => {
+		create_order => 7,
+		create_sql =>
+		    'INSERT INTO dump_test.test_second_table (col1, col2) '
+		  . 'SELECT generate_series, generate_series::text FROM generate_series(1,9);',
+		regexp => qr/^COPY test_second_table \(col1, col2\) FROM stdin;\n(?:\d\t\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY test_third_table' => {
+		create_order => 12,
+		create_sql =>
+			'INSERT INTO dump_test_second_schema.test_third_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,9);',
+		regexp => qr/^COPY test_third_table \(col1\) FROM stdin;\n(?:\d\n){9}\\\.\n$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_table' => {
+		regexp => qr/^(?:INSERT INTO test_table \(col1\) VALUES \(\d\);\n){9}$/m,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_second_table' => {
+		regexp => qr/^(?:INSERT INTO test_second_table \(col1, col2\) VALUES \(\d, '\d'\);\n){9}$/m,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_third_table' => {
+		regexp => qr/^(?:INSERT INTO test_third_table \(col1\) VALUES \(\d\);\n){9}$/m,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'COPY ... commands' => { # catch-all for COPY
+		regexp => qr/^COPY /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			binary_upgrade => 1,
+			column_inserts => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE ROLE dump_test' => {
+		create_order => 1,
+		create_sql => 'CREATE ROLE dump_test;',
+		regexp => qr/^CREATE ROLE dump_test;$/m,
+		like => {
+			pg_dumpall_globals => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE DATABASE postgres' => {
+		regexp => qr/^CREATE DATABASE postgres WITH TEMPLATE = template0 .*;$/m,
+		like => {
+			createdb => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE EXTENSION ... plpgsql' => {
+		regexp => qr/^CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE AGGREGATE dump_test.newavg' => {
+		create_order => 25,
+		create_sql => 'CREATE AGGREGATE dump_test.newavg (sfunc = int4_avg_accum, basetype = int4, stype = _int8, finalfunc = int8_avg, initcond1 = \'{0,0}\');',
+		regexp => qr/^CREATE AGGREGATE newavg\(integer\) \(\n\s+SFUNC = int4_avg_accum,\n\s+STYPE = bigint\[\],\n\s+INITCOND = \'\{0,0\}\',\n\s+FINALFUNC = int8_avg\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE DOMAIN dump_test.us_postal_code' => {
+		create_order => 29,
+		create_sql => 'CREATE DOMAIN dump_test.us_postal_code AS TEXT CHECK(VALUE ~ \'^\d{5}$\' OR VALUE ~ \'^\d{5}-\d{4}$\');',
+		regexp => qr/CREATE DOMAIN us_postal_code AS text\n\s+CONSTRAINT us_postal_code_check CHECK \(\(\(VALUE ~ \'\^\\d\{5\}\$\'::text\) OR \(VALUE ~ \'\^\\d\{5\}-\\d\{4\}\$\'::text\)\)\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.pltestlang_call_handler' => {
+		create_order => 17,
+		create_sql => 'CREATE FUNCTION dump_test.pltestlang_call_handler() RETURNS LANGUAGE_HANDLER AS \'$libdir/plpgsql\', \'plpgsql_call_handler\' LANGUAGE C;',
+		regexp => qr/^CREATE FUNCTION pltestlang_call_handler\(\) RETURNS language_handler\n\s+LANGUAGE c\n\s+AS '\$libdir\/plpgsql', 'plpgsql_call_handler';$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.trigger_func' => {
+		create_order => 30,
+		create_sql => 'CREATE FUNCTION dump_test.trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RETURN NULL; END;$$;',
+		regexp => qr/^CREATE FUNCTION trigger_func\(\) RETURNS trigger\n\s+LANGUAGE plpgsql\n\s+AS \$\$ BEGIN RETURN NULL; END;\$\$;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.event_trigger_func' => {
+		create_order => 32,
+		create_sql => 'CREATE FUNCTION dump_test.event_trigger_func() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN RETURN; END;$$;',
+		regexp => qr/^CREATE FUNCTION event_trigger_func\(\) RETURNS event_trigger\n\s+LANGUAGE plpgsql\n\s+AS \$\$ BEGIN RETURN; END;\$\$;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE EVENT TRIGGER test_event_trigger' => {
+		create_order => 33,
+		create_sql => 'CREATE EVENT TRIGGER test_event_trigger ON ddl_command_start EXECUTE PROCEDURE dump_test.event_trigger_func();',
+		regexp => qr/^CREATE EVENT TRIGGER test_event_trigger ON ddl_command_start\n\s+EXECUTE PROCEDURE dump_test\.event_trigger_func\(\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE TRIGGER test_trigger' => {
+		create_order => 31,
+		create_sql => 'CREATE TRIGGER test_trigger BEFORE INSERT ON dump_test.test_table FOR EACH ROW WHEN (NEW.col1 > 10) EXECUTE PROCEDURE dump_test.trigger_func();',
+		regexp => qr/^CREATE TRIGGER test_trigger BEFORE INSERT ON test_table FOR EACH ROW WHEN \(\(new.col1 > 10\)\) EXECUTE PROCEDURE trigger_func\(\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE TYPE dump_test.planets AS ENUM' => {
+		create_order => 37,
+		create_sql => 'CREATE TYPE dump_test.planets AS ENUM ( \'venus\', \'earth\', \'mars\' );',
+		regexp => qr/^CREATE TYPE planets AS ENUM \(\n\s+'venus',\n\s+'earth',\n\s+'mars'\n\);$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.planets AS ENUM pg_upgrade' => {
+		regexp => qr/^CREATE TYPE planets AS ENUM \(\n\);.*^ALTER TYPE dump_test\.planets ADD VALUE 'venus';\n.*^ALTER TYPE dump_test\.planets ADD VALUE 'earth';\n.*^ALTER TYPE dump_test\.planets ADD VALUE 'mars';\n$/ms,
+		like => {
+			binary_upgrade => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.textrange AS RANGE' => {
+		create_order => 38,
+		create_sql => 'CREATE TYPE dump_test.textrange AS RANGE (subtype=text, collation="C");',
+		regexp => qr/^CREATE TYPE textrange AS RANGE \(\n\s+subtype = text,\n\s+collation = pg_catalog\."C"\n\);/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.int42' => {
+		create_order => 39,
+		create_sql => 'CREATE TYPE dump_test.int42;',
+		regexp => qr/^CREATE TYPE int42;/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.int42_in' => {
+		create_order => 40,
+		create_sql => 'CREATE FUNCTION dump_test.int42_in(cstring) RETURNS dump_test.int42 AS \'int4in\' LANGUAGE internal STRICT IMMUTABLE;',
+		regexp => qr/^CREATE FUNCTION int42_in\(cstring\) RETURNS int42\n\s+LANGUAGE internal IMMUTABLE STRICT\n\s+AS \$\$int4in\$\$;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.int42_out' => {
+		create_order => 40,
+		create_sql => 'CREATE FUNCTION dump_test.int42_out(dump_test.int42) RETURNS cstring AS \'int4out\' LANGUAGE internal STRICT IMMUTABLE;',
+		regexp => qr/^CREATE FUNCTION int42_out\(int42\) RETURNS cstring\n\s+LANGUAGE internal IMMUTABLE STRICT\n\s+AS \$\$int4out\$\$;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.int42 populated' => {
+		create_order => 42,
+		create_sql => 'CREATE TYPE dump_test.int42 (internallength = 4, input = dump_test.int42_in, output = dump_test.int42_out, alignment = int4, default = 42, passedbyvalue);',
+		regexp => qr/^CREATE TYPE int42 \(\n\s+INTERNALLENGTH = 4,\n\s+INPUT = int42_in,\n\s+OUTPUT = int42_out,\n\s+DEFAULT = '42',\n\s+ALIGNMENT = int4,\n\s+STORAGE = plain,\n\s+PASSEDBYVALUE\n\);/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.composite' => {
+		create_order => 43,
+		create_sql => 'CREATE TYPE dump_test.composite AS (f1 int, f2 dump_test.int42);',
+		regexp => qr/^CREATE TYPE composite AS \(\n\s+f1 integer,\n\s+f2 int42\n\);/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FOREIGN DATA WRAPPER dummy' => {
+		create_order => 35,
+		create_sql => 'CREATE FOREIGN DATA WRAPPER dummy;',
+		regexp => qr/CREATE FOREIGN DATA WRAPPER dummy;/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy' => {
+		create_order => 36,
+		create_sql => 'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;',
+		regexp => qr/CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+#######################################
+# Currently broken.
+#######################################
+#
+#	'CREATE TRANSFORM FOR int' => {
+#		create_order => 34,
+#		create_sql => 'CREATE TRANSFORM FOR int LANGUAGE SQL (FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal));',
+#		regexp => qr/CREATE TRANSFORM FOR int LANGUAGE SQL \(FROM SQL WITH FUNCTION varchar_transform\(internal\), TO SQL WITH FUNCTION int4recv\(internal\)\);/m,
+#		like => {
+#			binary_upgrade => 1,
+#			clean => 1,
+#			clean_if_exists => 1,
+#			createdb => 1,
+#			defaults => 1,
+#			exclude_dump_test_schema => 1,
+#			exclude_test_table => 1,
+#			exclude_test_table_data => 1,
+#			no_privs => 1,
+#			no_owner => 1,
+#			schema_only => 1,
+#			section_post_data => 1,
+#		},
+#		unlike => {
+#			section_pre_data => 1,
+#			only_dump_test_schema => 1,
+#			only_dump_test_table => 1,
+#			pg_dumpall_globals => 1,
+#			test_schema_plus_blobs => 1,
+#		},
+#	},
+	'CREATE LANGUAGE pltestlang' => {
+		create_order => 18,
+		create_sql => 'CREATE LANGUAGE pltestlang HANDLER dump_test.pltestlang_call_handler;',
+		regexp => qr/^CREATE PROCEDURAL LANGUAGE pltestlang HANDLER pltestlang_call_handler;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE MATERIALIZED VIEW matview' => {
+		create_order => 20,
+		create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview (col1) AS SELECT * FROM dump_test.test_table;',
+		regexp => qr/^CREATE MATERIALIZED VIEW matview AS\n\s+SELECT test_table\.col1\n\s+FROM test_table\n\s+WITH NO DATA;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE MATERIALIZED VIEW matview_second' => {
+		create_order => 21,
+		create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview_second (col1) AS SELECT * FROM dump_test.matview;',
+		regexp => qr/^CREATE MATERIALIZED VIEW matview_second AS\n\s+SELECT matview\.col1\n\s+FROM matview\n\s+WITH NO DATA;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE POLICY p1 ON test_table' => {
+		create_order => 22,
+		create_sql => 'CREATE POLICY p1 ON dump_test.test_table USING (true) WITH CHECK (true);',
+		regexp => qr/^CREATE POLICY p1 ON test_table FOR ALL TO PUBLIC USING \(true\) WITH CHECK \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p2 ON test_table FOR SELECT' => {
+		create_order => 24,
+		create_sql => 'CREATE POLICY p2 ON dump_test.test_table FOR SELECT TO dump_test USING (true);',
+		regexp => qr/^CREATE POLICY p2 ON test_table FOR SELECT TO dump_test USING \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p3 ON test_table FOR INSERT' => {
+		create_order => 25,
+		create_sql => 'CREATE POLICY p3 ON dump_test.test_table FOR INSERT TO dump_test WITH CHECK (true);',
+		regexp => qr/^CREATE POLICY p3 ON test_table FOR INSERT TO dump_test WITH CHECK \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p4 ON test_table FOR UPDATE' => {
+		create_order => 26,
+		create_sql => 'CREATE POLICY p4 ON dump_test.test_table FOR UPDATE TO dump_test USING (true) WITH CHECK (true);',
+		regexp => qr/^CREATE POLICY p4 ON test_table FOR UPDATE TO dump_test USING \(true\) WITH CHECK \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p5 ON test_table FOR DELETE' => {
+		create_order => 27,
+		create_sql => 'CREATE POLICY p5 ON dump_test.test_table FOR DELETE TO dump_test USING (true);',
+		regexp => qr/^CREATE POLICY p5 ON test_table FOR DELETE TO dump_test USING \(true\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test' => {
+		create_order => 2,
+		create_sql => 'CREATE SCHEMA dump_test;',
+		regexp => qr/^CREATE SCHEMA dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test_second_schema' => {
+		create_order => 9,
+		create_sql => 'CREATE SCHEMA dump_test_second_schema;',
+		regexp => qr/^CREATE SCHEMA dump_test_second_schema;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE TABLE test_table' => {
+		create_order => 3,
+		create_sql => 'CREATE TABLE dump_test.test_table (col1 serial primary key, CHECK (col1 <= 1000));',
+		regexp => qr/^CREATE TABLE test_table \(\n\s+col1 integer NOT NULL,\n\s+CONSTRAINT test_table_col1_check CHECK \(\(col1 <= 1000\)\)\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE fk_reference_test_table' => {
+		create_order => 21,
+		create_sql => 'CREATE TABLE dump_test.fk_reference_test_table (col1 int primary key references dump_test.test_table);',
+		regexp => qr/^CREATE TABLE fk_reference_test_table \(\n\s+col1 integer NOT NULL\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE test_second_table' => {
+		create_order => 6,
+		create_sql => 'CREATE TABLE dump_test.test_second_table (col1 int, col2 text);',
+		regexp => qr/^CREATE TABLE test_second_table \(\n\s+col1 integer,\n\s+col2 text\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE test_third_table' => {
+		create_order => 11,
+		create_sql => 'CREATE TABLE dump_test_second_schema.test_third_table (col1 serial);',
+		regexp => qr/^CREATE TABLE test_third_table \(\n\s+col1 integer NOT NULL\n\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE SEQUENCE test_table_col1_seq' => {
+		regexp => qr/^CREATE SEQUENCE test_table_col1_seq\n\s+START WITH 1\n\s+INCREMENT BY 1\n\s+NO MINVALUE\n\s+NO MAXVALUE\n\s+CACHE 1;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE SEQUENCE test_third_table_col1_seq' => {
+		regexp => qr/^CREATE SEQUENCE test_third_table_col1_seq\n\s+START WITH 1\n\s+INCREMENT BY 1\n\s+NO MINVALUE\n\s+NO MAXVALUE\n\s+CACHE 1;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE UNIQUE INDEX test_third_table_idx ON test_third_table' => {
+		create_order => 13,
+		create_sql => 'CREATE UNIQUE INDEX test_third_table_idx ON dump_test_second_schema.test_third_table (col1);',
+		regexp => qr/^CREATE UNIQUE INDEX test_third_table_idx ON test_third_table USING btree \(col1\);$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE ... commands' => { # catch-all for CREATE
+		regexp => qr/^CREATE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			section_data => 1,
+		},
+	},
+	'DROP EXTENSION plpgsql' => {
+		regexp => qr/^DROP EXTENSION plpgsql;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP FUNCTION dump_test.pltestlang_call_handler()' => {
+		regexp => qr/^DROP FUNCTION dump_test\.pltestlang_call_handler\(\);$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP LANGUAGE pltestlang' => {
+		regexp => qr/^DROP PROCEDURAL LANGUAGE pltestlang;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test' => {
+		regexp => qr/^DROP SCHEMA dump_test;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA dump_test_second_schema;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE fk_reference_test_table' => {
+		regexp => qr/^DROP TABLE dump_test\.fk_reference_test_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_second_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_second_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_third_table' => {
+		regexp => qr/^DROP TABLE dump_test_second_schema\.test_third_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP EXTENSION IF EXISTS plpgsql' => {
+		regexp => qr/^DROP EXTENSION IF EXISTS plpgsql;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler()' => {
+		regexp => qr/^DROP FUNCTION IF EXISTS dump_test\.pltestlang_call_handler\(\);$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP LANGUAGE IF EXISTS pltestlang' => {
+		regexp => qr/^DROP PROCEDURAL LANGUAGE IF EXISTS pltestlang;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test_second_schema;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_second_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_second_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_third_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test_second_schema\.test_third_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP ... commands' => { # catch-all for DROP
+		regexp => qr/^DROP /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			binary_upgrade => 1,
+			column_inserts => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+		},
+	},
+	'GRANT USAGE ON SCHEMA dump_test_second_schema' => {
+		create_order => 10,
+		create_sql => 'GRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;',
+		regexp => qr/^GRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT SELECT ON TABLE test_table' => {
+		create_order => 5,
+		create_sql => 'GRANT SELECT ON TABLE dump_test.test_table TO dump_test;',
+		regexp => qr/^GRANT SELECT ON TABLE test_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'GRANT SELECT ON TABLE test_third_table' => {
+		create_order => 19,
+		create_sql => 'GRANT SELECT ON TABLE dump_test_second_schema.test_third_table TO dump_test;',
+		regexp => qr/^GRANT SELECT ON TABLE test_third_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT ALL ON SEQUENCE test_third_table_col1_seq' => {
+		create_order => 28,
+		create_sql => 'GRANT ALL ON SEQUENCE dump_test_second_schema.test_third_table_col1_seq TO dump_test;',
+		regexp => qr/^GRANT ALL ON SEQUENCE test_third_table_col1_seq TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT INSERT(col1) ON TABLE test_second_table' => {
+		create_order => 8,
+		create_sql => 'GRANT INSERT (col1) ON TABLE dump_test.test_second_table TO dump_test;',
+		regexp => qr/^GRANT INSERT\(col1\) ON TABLE test_second_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'GRANT EXECUTE ON FUNCTION pg_sleep() TO dump_test' => {
+		create_order => 16,
+		create_sql => 'GRANT EXECUTE ON FUNCTION pg_sleep(float8) TO dump_test;',
+		regexp => qr/^GRANT ALL ON FUNCTION pg_sleep\(double precision\) TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT commands' => { # catch-all for GRANT commands
+		regexp => qr/^GRANT /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			no_privs => 1,
+			section_data => 1,
+		},
+	},
+	'REFRESH MATERIALIZED VIEW matview' => {
+		regexp => qr/^REFRESH MATERIALIZED VIEW matview;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+	},
+	'REFRESH MATERIALIZED VIEW matview_second' => {
+		regexp => qr/^REFRESH MATERIALIZED VIEW matview;\n.*REFRESH MATERIALIZED VIEW matview_second;$/ms,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+	},
+	'REVOKE EXECUTE ON FUNCTION pg_sleep() FROM public' => {
+		create_order => 15,
+		create_sql => 'REVOKE EXECUTE ON FUNCTION pg_sleep(float8) FROM public;',
+		regexp => qr/^REVOKE ALL ON FUNCTION pg_sleep\(double precision\) FROM PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE CREATE ON SCHEMA public FROM public' => {
+		create_order => 16,
+		create_sql => 'REVOKE CREATE ON SCHEMA public FROM public;',
+		regexp => qr/^REVOKE ALL ON SCHEMA public FROM PUBLIC;\nGRANT USAGE ON SCHEMA public TO PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE USAGE ON LANGUAGE plpgsql FROM public' => {
+		create_order => 16,
+		create_sql => 'REVOKE USAGE ON LANGUAGE plpgsql FROM public;',
+		regexp => qr/^REVOKE ALL ON LANGUAGE plpgsql FROM PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE commands' => { # catch-all for REVOKE commands
+		regexp => qr/^REVOKE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			no_privs => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+);
+
+#########################################
+# Create a PG instance to test actually dumping from
+
+my $node = get_new_node('main');
+$node->init;
+$node->start;
+
+my $port = $node->port;
+
+# Start with 2 because of command_exit_is() tests below
+my $num_tests = 2;
+
+foreach my $run (sort keys %pgdump_runs) {
+	my $test_key = $run;
+
+	# Each run of pg_dump is a test itself
+	$num_tests++;
+
+	# If there is a restore cmd, that's another test
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$num_tests++;
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	# Then count all the tests run against each run
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			$num_tests++;
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			$num_tests++;
+		}
+	}
+}
+plan tests => $num_tests;
+
+#########################################
+# Set up schemas, tables, etc, to be dumped.
+
+# Build up the create statements
+my $create_sql = '';
+
+foreach my $test (
+	sort {
+		if ($tests{$a}->{create_order} and $tests{$b}->{create_order}) {
+			$tests{$a}->{create_order} <=> $tests{$b}->{create_order};
+		} elsif ($tests{$a}->{create_order}) {
+			-1;
+		} elsif ($tests{$b}->{create_order}) {
+			1;
+		} else {
+			0;
+		}
+	} keys %tests) {
+	if ($tests{$test}->{create_sql}) {
+		$create_sql .= $tests{$test}->{create_sql};
+	}
+}
+
+# Send the combined set of commands to psql
+$node->safe_psql('postgres', $create_sql);
+
+#########################################
+# Test connecting to a non-existent database
+
+command_exit_is([ 'pg_dump', '-p', "$port", 'qqq' ],
+	1, 'pg_dump: [archiver (db)] connection to database "qqq" failed: FATAL:  database "qqq" does not exist');
+
+command_exit_is([ 'pg_dump', '-p', "$port", '--role=dump_test' ],
+	1, 'pg_dump: [archiver (db)] query failed: ERROR:  permission denied for');
+
+#########################################
+# Run all runs
+
+foreach my $run (sort keys %pgdump_runs) {
+
+	my $test_key = $run;
+
+	$node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs");
+
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$node->command_ok(\@{ $pgdump_runs{$run}->{restore_cmd} }, "$run: pg_restore runs");
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	my $output_file = slurp_file("$tempdir/${run}.sql");
+
+	#########################################
+	# Run all tests where this run is included
+	# as either a 'like' or 'unlike' test.
+
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			like($output_file, $tests{$test}->{regexp}, "$run: dumps $test");
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			unlike($output_file, $tests{$test}->{regexp}, "$run: does not dump $test");
+		}
+	}
+}
+
+#########################################
+# Stop the database instance, which will be removed at the end of the tests.
+
+$node->stop('fast');
-- 
2.5.0

#29Noah Misch
noah@leadboat.com
In reply to: Stephen Frost (#27)

On Wed, May 04, 2016 at 08:14:55AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Mon, Apr 25, 2016 at 12:39:09AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Fri, Apr 22, 2016 at 12:31:41PM -0400, Stephen Frost wrote:

After looking through the code a bit, I realized that there are a lot of
object types which don't have ACLs at all but which exist in pg_catalog
and were being analyzed because the bitmask for pg_catalog included ACLs
and therefore was non-zero.

Clearing that bit for object types which don't have ACLs improved the
performance for empty databases quite a bit (from about 3s to a bit
under 1s on my laptop). That's a 42-line patch, with comment lines
being half of that, which I'll push once I've looked into the other
concerns which were brought up on this thread.

That's good news.

Attached patch-set includes this change in patch #2.

Timings for the 100-database pg_dumpall:

HEAD: 131s
HEAD+patch: 33s
9.5: 8.6s

Nice improvement for such a simple patch.

Patch #2 in the attached patchset includes that improvement and a
further one which returns the performance to very close to 9.5.

What timings did you measure? (How close?)

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#29)

* Noah Misch (noah@leadboat.com) wrote:

On Wed, May 04, 2016 at 08:14:55AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Mon, Apr 25, 2016 at 12:39:09AM -0400, Stephen Frost wrote:

* Noah Misch (noah@leadboat.com) wrote:

On Fri, Apr 22, 2016 at 12:31:41PM -0400, Stephen Frost wrote:

After looking through the code a bit, I realized that there are a lot of
object types which don't have ACLs at all but which exist in pg_catalog
and were being analyzed because the bitmask for pg_catalog included ACLs
and therefore was non-zero.

Clearing that bit for object types which don't have ACLs improved the
performance for empty databases quite a bit (from about 3s to a bit
under 1s on my laptop). That's a 42-line patch, with comment lines
being half of that, which I'll push once I've looked into the other
concerns which were brought up on this thread.

That's good news.

Attached patch-set includes this change in patch #2.

Timings for the 100-database pg_dumpall:

HEAD: 131s
HEAD+patch: 33s
9.5: 8.6s

Nice improvement for such a simple patch.

Patch #2 in the attached patchset includes that improvement and a
further one which returns the performance to very close to 9.5.

What timings did you measure? (How close?)

On my laptop, with 100 databases, I get:

9.5: 0m3.306s, 0m3.290s, 0m3.309s, avg: 3.302
HEAD+patch: 0m4.681s, 0m4.681s, 0m4.709s, avg: 4.690

9.5 was installed from Debian packages, HEAD+patch was built with -O2,
no debugging, no casserts, though it's entirely possible I've got
something else enabled in my builds that slow it down a bit.

In any case, as I was saying, that's far closer to 9.5 run-time. I've
not measured the time added when things like TRANSFORMs were added, but
it wouldn't surprise me if adding a new query for every database to
pg_dump adds something similar to this difference.

Thanks!

Stephen

#31Stephen Frost
sfrost@snowman.net
In reply to: Stephen Frost (#30)
1 attachment(s)

* Stephen Frost (sfrost@snowman.net) wrote:

In any case, as I was saying, that's far closer to 9.5 run-time. I've
not measured the time added when things like TRANSFORMs were added, but
it wouldn't surprise me if adding a new query for every database to
pg_dump adds something similar to this difference.

Updated patch attached.

This adds the same kind of test suite to a new
'src/test/modules/test_pg_dump' for testing pg_dump with extensions.
I'm going to flesh that out tomorrow with some real tests. Today was
spent mostly setting up that test suite and spending quite a bit of time
cleaning up the src/bin/pg_dump/t tests, to make it easier for others to
review and make sense of the regexp's and whatnot that are included.

Also updated the skipping of LOCK TABLE, per comments from Tom.

I should be able to get the testing that I want added to test_pg_dump
tomorrow and will push all of this once that's included. I'd really
like to make sure that we've got coverage of initial privileges in
extensions with pg_dump, which is why I've been working on this today
and haven't pushed the patch-set yet. I'm pretty sure they work as
expected, but we should be testing it through the buildfarm.

Thanks!

Stephen

Attachments:

pg_dump_improvements_v4.patchtext/x-diff; charset=us-asciiDownload
From 1e3d3053d9cbb309af0307e31ddea92999d9ed15 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Sun, 24 Apr 2016 23:59:23 -0400
Subject: [PATCH 1/4] Correct pg_dump WHERE clause for functions/aggregates

The query to grab the function/aggregate information is now joining
to pg_init_privs, so we can simplify (and correct) the WHERE clause
used to determine if a given function's ACL has changed from the
initial ACL on the function.

Bug found by Noah, patch by me.
---
 src/bin/pg_dump/pg_dump.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d3f5157..bb33075 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -4673,11 +4673,7 @@ getAggregates(Archive *fout, int *numAggs)
 						  "p.pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  username_subquery,
 						  acl_subquery->data,
 						  racl_subquery->data,
@@ -4923,11 +4919,7 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "pronamespace != "
 						  "(SELECT oid FROM pg_namespace "
 						  "WHERE nspname = 'pg_catalog') OR "
-						  "EXISTS (SELECT * FROM pg_init_privs pip "
-						  "WHERE p.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_proc') "
-						  "AND p.proacl IS DISTINCT FROM pip.initprivs)",
+						  "p.proacl IS DISTINCT FROM pip.initprivs",
 						  acl_subquery->data,
 						  racl_subquery->data,
 						  initacl_subquery->data,
-- 
2.5.0


From 374d17371aff04f3887fa980337154b5c2e8db22 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:00:15 -0400
Subject: [PATCH 2/4] pg_dump performance and other fixes

Do not try to dump objects which do not have ACLs when only ACLs are
being requested.  This results in a significant performance improvement
as we can avoid querying for further information on these objects when
we don't need to.

When limiting the components to dump for an extension, consider what
components have been requested.  Initially, we incorrectly hard-coded
the components of the extension objects to dump, which would mean that
we wouldn't dump some components even with they were asked for and in
other cases we would dump components which weren't requested.

Correct defaultACLs to use 'dump_contains' instead of 'dump'.  The
defaultACL is considered a member of the namespace and should be
dumped based on the same set of components that the other objects in
the schema are, not based on what we're dumping for the namespace
itself (which might not include ACLs, if the namespace has just the
default or initial ACL).

Use DUMP_COMPONENT_ACL for from-initdb objects, to allow users to
change their ACLs, should they wish to.  This just extends what we
are doing for the pg_catalog namespace to objects which are not
members of namespaces.
---
 src/bin/pg_dump/pg_dump.c | 176 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 149 insertions(+), 27 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index bb33075..d826b4d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1297,14 +1297,17 @@ checkExtensionMembership(DumpableObject *dobj, Archive *fout)
 	 * contents rather than replace the extension contents with something
 	 * different.
 	 */
-	if (!fout->dopt->binary_upgrade && fout->remoteVersion >= 90600)
-		dobj->dump = DUMP_COMPONENT_ACL |
-			DUMP_COMPONENT_SECLABEL |
-			DUMP_COMPONENT_POLICY;
-	else if (!fout->dopt->binary_upgrade)
-		dobj->dump = DUMP_COMPONENT_NONE;
-	else
+	if (fout->dopt->binary_upgrade)
 		dobj->dump = ext->dobj.dump;
+	else
+	{
+		if (fout->remoteVersion < 90600)
+			dobj->dump = DUMP_COMPONENT_NONE;
+		else
+			dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
+					DUMP_COMPONENT_SECLABEL | DUMP_COMPONENT_POLICY);
+
+	}
 
 	return true;
 }
@@ -1452,7 +1455,7 @@ selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
 
 	if (dinfo->dobj.namespace)
 		/* default ACLs are considered part of the namespace */
-		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
+		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
 	else
 		dinfo->dobj.dump = dopt->include_everything ?
 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
@@ -1473,6 +1476,10 @@ selectDumpableCast(CastInfo *cast, Archive *fout)
 	if (checkExtensionMembership(&cast->dobj, fout))
 		return;					/* extension membership overrides all else */
 
+	/*
+	 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
+	 * support ACLs currently.
+	 */
 	if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
@@ -1494,11 +1501,23 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
 	if (checkExtensionMembership(&plang->dobj, fout))
 		return;					/* extension membership overrides all else */
 
-	if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
+	/*
+	 * Only include procedural languages when we are dumping everything.
+	 *
+	 * For from-initdb procedural languages, only include ACLs, as we do for
+	 * the pg_catalog namespace.  We need this because procedural languages do
+	 * not live in any namespace.
+	 */
+	if (!fout->dopt->include_everything)
 		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
-		plang->dobj.dump = fout->dopt->include_everything ?
-			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+	{
+		if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
+			plang->dobj.dump = fout->remoteVersion < 90600 ?
+				DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
+		else
+			plang->dobj.dump = DUMP_COMPONENT_ALL;
+	}
 }
 
 /*
@@ -1515,6 +1534,10 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 	if (checkExtensionMembership(&method->dobj, fout))
 		return;					/* extension membership overrides all else */
 
+	/*
+	 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
+	 * they do not support ACLs currently.
+	 */
 	if (method->dobj.catId.oid < (Oid) FirstNormalObjectId)
 		method->dobj.dump = DUMP_COMPONENT_NONE;
 	else
@@ -1535,11 +1558,17 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 static void
 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 {
+	/*
+	 * Use DUMP_COMPONENT_ACL for from-initdb extensions, to allow users
+	 * to change permissions on those objects, if they wish to, and have
+	 * those changes preserved.
+	 */
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = DUMP_COMPONENT_NONE;
+		extinfo->dobj.dump = DUMP_COMPONENT_ACL;
 	else
-		extinfo->dobj.dump = dopt->include_everything ?
-			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
+		extinfo->dobj.dump = extinfo->dobj.dump_contains =
+			dopt->include_everything ?  DUMP_COMPONENT_ALL :
+				DUMP_COMPONENT_NONE;
 }
 
 /*
@@ -4175,6 +4204,9 @@ getOperators(Archive *fout, int *numOprs)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(oprinfo[i].dobj), fout);
 
+		/* Operators do not currently have ACLs. */
+		oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (strlen(oprinfo[i].rolname) == 0)
 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
 					  oprinfo[i].dobj.name);
@@ -4259,6 +4291,9 @@ getCollations(Archive *fout, int *numCollations)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(collinfo[i].dobj), fout);
+
+		/* Collations do not currently have ACLs. */
+		collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4340,6 +4375,9 @@ getConversions(Archive *fout, int *numConversions)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(convinfo[i].dobj), fout);
+
+		/* Conversions do not currently have ACLs. */
+		convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4413,6 +4451,9 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
 
 		/* Decide whether we want to dump it */
 		selectDumpableAccessMethod(&(aminfo[i]), fout);
+
+		/* Access methods do not currently have ACLs. */
+		aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -4506,6 +4547,9 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opcinfo[i].dobj), fout);
 
+		/* Op Classes do not currently have ACLs. */
+		opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opcinfo[i].rolname) == 0)
@@ -4594,6 +4638,9 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(opfinfo[i].dobj), fout);
 
+		/* Extensions do not currently have ACLs. */
+		opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		if (fout->remoteVersion >= 70300)
 		{
 			if (strlen(opfinfo[i].rolname) == 0)
@@ -5123,6 +5170,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_toastreloptions;
 	int			i_reloftype;
 	int			i_relpages;
+	int			i_changed_acl;
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, "pg_catalog");
@@ -5154,6 +5202,11 @@ getTables(Archive *fout, int *numTables)
 		PQExpBuffer initacl_subquery = createPQExpBuffer();
 		PQExpBuffer initracl_subquery = createPQExpBuffer();
 
+		PQExpBuffer attacl_subquery = createPQExpBuffer();
+		PQExpBuffer attracl_subquery = createPQExpBuffer();
+		PQExpBuffer attinitacl_subquery = createPQExpBuffer();
+		PQExpBuffer attinitracl_subquery = createPQExpBuffer();
+
 		/*
 		 * Left join to pick up dependency info linking sequences to their
 		 * owning column, if any (note this dependency is AUTO as of 8.2)
@@ -5167,6 +5220,10 @@ getTables(Archive *fout, int *numTables)
 				 "CASE WHEN c.relkind = 'S' THEN 's' ELSE 'r' END::\"char\"",
 						dopt->binary_upgrade);
 
+		buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
+						attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
+						dopt->binary_upgrade);
+
 		appendPQExpBuffer(query,
 						  "SELECT c.tableoid, c.oid, c.relname, "
 						  "%s AS relacl, %s as rrelacl, "
@@ -5188,7 +5245,17 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON"
+						  "(c.oid = pip.objoid AND pip.classoid = "
+						  "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND pip.objsubid = at.attnum)"
+						  "WHERE at.attrelid = c.oid AND ("
+						  "%s IS NOT NULL "
+						  "OR %s IS NOT NULL "
+						  "OR %s IS NOT NULL "
+						  "OR %s IS NOT NULL"
+						  "))"
+						  "AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5207,6 +5274,10 @@ getTables(Archive *fout, int *numTables)
 						  initacl_subquery->data,
 						  initracl_subquery->data,
 						  username_subquery,
+						  attacl_subquery->data,
+						  attracl_subquery->data,
+						  attinitacl_subquery->data,
+						  attinitracl_subquery->data,
 						  RELKIND_SEQUENCE,
 						  RELKIND_RELATION, RELKIND_SEQUENCE,
 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
@@ -5216,6 +5287,11 @@ getTables(Archive *fout, int *numTables)
 		destroyPQExpBuffer(racl_subquery);
 		destroyPQExpBuffer(initacl_subquery);
 		destroyPQExpBuffer(initracl_subquery);
+
+		destroyPQExpBuffer(attacl_subquery);
+		destroyPQExpBuffer(attracl_subquery);
+		destroyPQExpBuffer(attinitacl_subquery);
+		destroyPQExpBuffer(attinitracl_subquery);
 	}
 	else if (fout->remoteVersion >= 90500)
 	{
@@ -5245,7 +5321,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5290,7 +5367,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5335,7 +5413,8 @@ getTables(Archive *fout, int *numTables)
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5378,7 +5457,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5421,7 +5501,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5463,7 +5544,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "tc.reloptions AS toast_reloptions "
+						  "tc.reloptions AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5505,7 +5587,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5546,7 +5629,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5586,7 +5670,8 @@ getTables(Archive *fout, int *numTables)
 						  "d.refobjsubid AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "LEFT JOIN pg_depend d ON "
 						  "(c.relkind = '%c' AND "
@@ -5623,7 +5708,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5655,7 +5741,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class "
 						  "WHERE relkind IN ('%c', '%c', '%c') "
 						  "ORDER BY oid",
@@ -5695,7 +5782,8 @@ getTables(Archive *fout, int *numTables)
 						  "NULL::int4 AS owning_col, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
-						  "NULL AS toast_reloptions "
+						  "NULL AS toast_reloptions, "
+						  "NULL AS changed_acl "
 						  "FROM pg_class c "
 						  "WHERE relkind IN ('%c', '%c') "
 						  "ORDER BY oid",
@@ -5754,6 +5842,7 @@ getTables(Archive *fout, int *numTables)
 	i_checkoption = PQfnumber(res, "checkoption");
 	i_toastreloptions = PQfnumber(res, "toast_reloptions");
 	i_reloftype = PQfnumber(res, "reloftype");
+	i_changed_acl = PQfnumber(res, "changed_acl");
 
 	if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
 	{
@@ -5835,6 +5924,21 @@ getTables(Archive *fout, int *numTables)
 		else
 			selectDumpableTable(&tblinfo[i], fout);
 
+		/*
+		 * If the table-level and all column-level ACLs for this table are
+		 * unchanged, then we don't need to worry about including the ACLs
+		 * for this table.  If any column-level ACLs have been changed, the
+		 * 'changed_acl' column from the query will indicate that.
+		 *
+		 * This can result in a significant performance improvement in cases
+		 * where we are only looking to dump out the ACL (eg: pg_catalog).
+		 */
+		if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
+			PQgetisnull(res, i, i_initrelacl) &&
+			PQgetisnull(res, i, i_initrrelacl) &&
+			strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
+			tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
+
 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
 
 		tblinfo[i].postponed_def = false;		/* might get set during sort */
@@ -6989,6 +7093,9 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(evtinfo[i].dobj), fout);
+
+		/* Event Triggers do not currently have ACLs. */
+		evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -7350,6 +7457,9 @@ getCasts(Archive *fout, int *numCasts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableCast(&(castinfo[i]), fout);
+
+		/* Casts do not currently have ACLs. */
+		castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8143,6 +8253,9 @@ getTSParsers(Archive *fout, int *numTSParsers)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(prsinfo[i].dobj), fout);
+
+		/* Text Search Parsers do not currently have ACLs. */
+		prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8228,6 +8341,9 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(dictinfo[i].dobj), fout);
+
+		/* Text Search Dictionaries do not currently have ACLs. */
+		dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8305,6 +8421,9 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(tmplinfo[i].dobj), fout);
+
+		/* Text Search Templates do not currently have ACLs. */
+		tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
@@ -8383,6 +8502,9 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 
 		/* Decide whether we want to dump it */
 		selectDumpableObject(&(cfginfo[i].dobj), fout);
+
+		/* Text Search Configurations do not currently have ACLs. */
+		cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 	}
 
 	PQclear(res);
-- 
2.5.0


From 918743ef646b7a1b5aafc9314bdc8832963e6d69 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Wed, 4 May 2016 13:40:36 -0400
Subject: [PATCH 3/4] Only issue LOCK TABLE commands when necessary

Reviewing the cases where we need to LOCK a given table during a dump,
it was pointed out by Tom that we really don't need to LOCK a table if
we are only looking to dump the ACL for it, or certain other
components.  After reviewing the queries run for all of the component
pieces, a list of components were determined to not require LOCK'ing
of the table.

This implements a check to avoid LOCK'ing those tables.

Initial complaint from Rushabh Lathia, discussed with Robert and Tom,
the patch is mine.
---
 src/bin/pg_dump/pg_dump.c |  5 ++++-
 src/bin/pg_dump/pg_dump.h | 27 +++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index d826b4d..adf0c99 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -5953,8 +5953,11 @@ getTables(Archive *fout, int *numTables)
 		 *
 		 * NOTE: it'd be kinda nice to lock other relations too, not only
 		 * plain tables, but the backend doesn't presently allow that.
+		 *
+		 * We only need to lock the table for certain components; see pg_dump.h
 		 */
-		if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
+		if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION &&
+				(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
 		{
 			resetPQExpBuffer(query);
 			appendPQExpBuffer(query,
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 7314cbe..2bfa2d9 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -93,6 +93,33 @@ typedef uint32 DumpComponents;	/* a bitmask of dump object components */
 #define DUMP_COMPONENT_USERMAP		(1 << 6)
 #define DUMP_COMPONENT_ALL			(0xFFFF)
 
+/*
+ * component types which require us to obtain a lock on the table
+ *
+ * Note that some components only require looking at the information
+ * in the pg_catalog tables and, for those components, we do not need
+ * to lock the table.  Be careful here though- some components use
+ * server-side functions which pull the latest information from
+ * SysCache and in those cases we *do* need to lock the table.
+ *
+ * We do not need locks for the COMMENT and SECLABEL components as
+ * those simply query their associated tables without using any
+ * server-side functions.  We do not need locks for the ACL component
+ * as we pull that information from pg_class without using any
+ * server-side functions that use SysCache.  The USERMAP component
+ * is only relevant for FOREIGN SERVERs and not tables, so no sense
+ * locking a table for that either (that can happen if we are going
+ * to dump "ALL" components for a table).
+ *
+ * We DO need locks for DEFINITION, due to various server-side
+ * functions that are used and POLICY due to pg_get_expr().  We set
+ * this up to grab the lock except in the cases we know to be safe.
+ */
+#define DUMP_COMPONENTS_REQUIRING_LOCK (\
+		DUMP_COMPONENT_DEFINITION |\
+		DUMP_COMPONENT_DATA |\
+		DUMP_COMPONENT_POLICY)
+
 typedef struct _dumpableObject
 {
 	DumpableObjectType objType;
-- 
2.5.0


From 17ef28a2f5d18eaff23ed8d611e585fc36fe2434 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 25 Apr 2016 00:01:38 -0400
Subject: [PATCH 4/4] Add TAP tests for pg_dump

This TAP test suite will create a new cluster, populate it based on
the 'create_sql' values in the '%tests' hash, run all of the runs
defined in the '%pgdump_runs' hash, and then for each test in the
'%tests' hash, compare each run's output the the regular expression
defined for the test under the 'like' and 'unlike' functions, as
appropriate.

While this test suite covers a fair bit of ground (67% of pg_dump.c
and quite a bit of the other files in src/bin/pg_dump), there is
still quite a bit which remains to be added to provide better code
coverage.  Still, this is quite a bit better than we had, and has
found a few bugs already (note that the CREATE TRANSFORM test is
commented out, as it is currently failing).

Idea for using the TAP system from Tom, though all of the code is mine.
---
 src/bin/pg_dump/Makefile                           |    3 +
 src/bin/pg_dump/pg_dump.c                          |    2 +-
 src/bin/pg_dump/t/001_basic.pl                     |   42 +
 src/bin/pg_dump/t/002_pg_dump.pl                   | 2859 ++++++++++++++++++++
 src/test/modules/Makefile                          |    1 +
 src/test/modules/test_pg_dump/.gitignore           |    4 +
 src/test/modules/test_pg_dump/Makefile             |   25 +
 src/test/modules/test_pg_dump/README               |    2 +
 .../modules/test_pg_dump/expected/test_pg_dump.out |    6 +
 src/test/modules/test_pg_dump/sql/test_pg_dump.sql |    1 +
 src/test/modules/test_pg_dump/t/001_base.pl        |  403 +++
 .../modules/test_pg_dump/test_pg_dump--1.0.sql     |    8 +
 src/test/modules/test_pg_dump/test_pg_dump.control |    3 +
 13 files changed, 3358 insertions(+), 1 deletion(-)
 create mode 100644 src/bin/pg_dump/t/001_basic.pl
 create mode 100644 src/bin/pg_dump/t/002_pg_dump.pl
 create mode 100644 src/test/modules/test_pg_dump/.gitignore
 create mode 100644 src/test/modules/test_pg_dump/Makefile
 create mode 100644 src/test/modules/test_pg_dump/README
 create mode 100644 src/test/modules/test_pg_dump/expected/test_pg_dump.out
 create mode 100644 src/test/modules/test_pg_dump/sql/test_pg_dump.sql
 create mode 100644 src/test/modules/test_pg_dump/t/001_base.pl
 create mode 100644 src/test/modules/test_pg_dump/test_pg_dump--1.0.sql
 create mode 100644 src/test/modules/test_pg_dump/test_pg_dump.control

diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index 9596789..260804b 100644
--- a/src/bin/pg_dump/Makefile
+++ b/src/bin/pg_dump/Makefile
@@ -42,6 +42,9 @@ install: all installdirs
 installdirs:
 	$(MKDIR_P) '$(DESTDIR)$(bindir)'
 
+check:
+	$(prove_check)
+
 uninstall:
 	rm -f $(addprefix '$(DESTDIR)$(bindir)'/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X))
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index adf0c99..7d63cde 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1564,7 +1564,7 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 	 * those changes preserved.
 	 */
 	if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
-		extinfo->dobj.dump = DUMP_COMPONENT_ACL;
+		extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
 	else
 		extinfo->dobj.dump = extinfo->dobj.dump_contains =
 			dopt->include_everything ?  DUMP_COMPONENT_ALL :
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
new file mode 100644
index 0000000..1411ef7
--- /dev/null
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -0,0 +1,42 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More tests => 15;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+#########################################
+# Basic checks
+
+program_help_ok('pg_dump');
+program_version_ok('pg_dump');
+program_options_handling_ok('pg_dump');
+
+#########################################
+# Test various invalid options and disallowed combinations
+# Doesn't require a PG instance to be set up, so do this first.
+
+command_exit_is([ 'pg_dump', 'qqq', 'abc' ],
+	1, 'pg_dump: too many command-line arguments (first is "asd")');
+
+command_exit_is([ 'pg_dump', '-s', '-a' ],
+	1, 'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '-c', '-a' ],
+	1, 'pg_dump: options -c/--clean and -a/--data-only cannot be used together');
+
+command_exit_is([ 'pg_dump', '--inserts', '-o' ],
+	1, 'pg_dump: options --inserts/--column-inserts and -o/--oids cannot be used together');
+
+command_exit_is([ 'pg_dump', '--if-exists' ],
+	1, 'pg_dump: option --if-exists requires option -c/--clean');
+
+command_exit_is([ 'pg_dump', '-j' ],
+	1, 'pg_dump: option requires an argument -- \'j\'');
+
+command_exit_is([ 'pg_dump', '-j3' ],
+	1, 'pg_dump: parallel backup only supported by the directory format');
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
new file mode 100644
index 0000000..bd1fa35
--- /dev/null
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -0,0 +1,2859 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+###############################################################
+# Definition of the pg_dump runs to make.
+#
+# Each of these runs are named and those names are used below
+# to define how each test should (or shouldn't) treat a result
+# from a given run.
+#
+# test_key indicates that a given run should simply use the same
+# set of like/unlike tests as another run, and which run that is.
+#
+# dump_cmd is the pg_dump command to run, which is an array of
+# the full command and arguments to run.  Note that this is run
+# using $node->command_ok(), so the port does not need to be
+# specified and is pulled from $PGPORT, which is set by the
+# PostgresNode system.
+#
+# restore_cmd is the pg_restore command to run, if any.  Note
+# that this should generally be used when the pg_dump goes to
+# a non-text file and that the restore can then be used to
+# generate a text file to run through the tests from the
+# non-text file generated by pg_dump.
+#
+# TODO: Have pg_restore actually restore to an independent
+# database and then pg_dump *that* database (or something along
+# those lines) to validate that part of the process.
+
+my %pgdump_runs = (
+	binary_upgrade => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/binary_upgrade.sql",
+			'--schema-only',
+			'--binary-upgrade',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean.sql",
+			'-c',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean_if_exists => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean_if_exists.sql",
+			'-c',
+			'--if-exists',
+			'-E', 'UTF8', # no-op, just tests that option is accepted
+			'postgres',
+		],
+	},
+	column_inserts => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/column_inserts.sql",
+			'-a',
+			'--column-inserts',
+			'postgres',
+		],
+	},
+	createdb => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/createdb.sql",
+			'-C',
+			'-R', # no-op, just for testing
+			'postgres',
+		],
+	},
+	data_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/data_only.sql",
+			'-a',
+			'-v', # no-op, just make sure it works
+			'postgres',
+		],
+	},
+	defaults => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/defaults.sql",
+			'postgres',
+		],
+	},
+	defaults_custom_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fc',
+			'-Z6',
+			'-f', "$tempdir/defaults_custom_format.dump",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_custom_format.sql",
+			"$tempdir/defaults_custom_format.dump",
+		],
+	},
+	defaults_dir_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-f', "$tempdir/defaults_dir_format",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_dir_format.sql",
+			"$tempdir/defaults_dir_format",
+		],
+	},
+	defaults_parallel => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-j2',
+			'-f', "$tempdir/defaults_parallel",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_parallel.sql",
+			"$tempdir/defaults_parallel",
+		],
+	},
+	defaults_tar_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Ft',
+			'-f', "$tempdir/defaults_tar_format.tar",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_tar_format.sql",
+			"$tempdir/defaults_tar_format.tar",
+		],
+	},
+	exclude_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_dump_test_schema.sql",
+			'-N', 'dump_test',
+			'postgres',
+		],
+	},
+	exclude_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table.sql",
+			'-T', 'dump_test.test_table',
+			'postgres',
+		],
+	},
+	exclude_test_table_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/exclude_test_table_data.sql",
+			'--exclude-table-data=dump_test.test_table',
+			'postgres',
+		],
+	},
+	pg_dumpall_globals => {
+		dump_cmd => [
+			'pg_dumpall',
+			'-f', "$tempdir/pg_dumpall_globals.sql",
+			'-g',
+		],
+	},
+	no_privs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_privs.sql",
+			'-x',
+			'postgres',
+		],
+	},
+	no_owner => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_owner.sql",
+			'-O',
+			'postgres',
+		],
+	},
+	only_dump_test_schema => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_schema.sql",
+			'-n', 'dump_test',
+			'postgres',
+		],
+	},
+	only_dump_test_table => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/only_dump_test_table.sql",
+			'-t', 'dump_test.test_table',
+			'--lock-wait-timeout=1000000',
+			'postgres',
+		],
+	},
+	role => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/role.sql",
+			'--role=dump_test',
+			'--schema=dump_test_second_schema',
+			'postgres',
+		],
+	},
+	schema_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/schema_only.sql",
+			'-s',
+			'postgres',
+		],
+	},
+	section_pre_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_pre_data.sql",
+			'--section=pre-data',
+			'postgres',
+		],
+	},
+	section_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_data.sql",
+			'--section=data',
+			'postgres',
+		],
+	},
+	section_post_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_post_data.sql",
+			'--section=post-data',
+			'postgres',
+		],
+	},
+	test_schema_plus_blobs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/test_schema_plus_blobs.sql",
+			'-n', 'dump_test',
+			'-b',
+			'postgres',
+		],
+	},
+);
+
+###############################################################
+# Definition of the tests to run.
+#
+# Each test is defined using the log message that will be used.
+#
+# A regexp should be defined for each test which provides the
+# basis for the test.  That regexp will be run against the output
+# file of each of the runs which the test is to be run against
+# and the success of the result will depend on if the regexp
+# result matches the expected 'like' or 'unlike' case.
+#
+# For each test, there are two sets of runs defined, one for
+# the 'like' tests and one for the 'unlike' tests.  'like'
+# essentially means "the regexp for this test must match the
+# output file".  'unlike' is the opposite.
+#
+# There are a few 'catch-all' tests which can be used to have
+# a single, simple, test to over a range of other tests.  For
+# example, there is a '^CREATE ' test, which is used for the
+# 'data-only' test as there should never be any kind of CREATE
+# statement in a 'data-only' run.  Without the catch-all, we
+# would have to list the 'data-only' run in each and every
+# 'CREATE xxxx' test, which would be a lot of additional tests.
+#
+# Note that it makes no sense for the same run to ever be listed
+# in both 'like' and 'unlike' categories.
+#
+# There can then be a 'create_sql' and 'create_order' for a
+# given test.  The 'create_sql' commands are collected up in
+# 'create_order' and then run against the database prior to any
+# of the pg_dump runs happening.  This is what "seeds" the
+# system with objects to be dumped out.
+#
+# Building of this hash takes a bit of time as all of the regexps
+# included in it are compiled.  This greatly improves performance
+# as the regexps are used for each run the test applies to.
+
+my %tests = (
+	'ALTER DEFAULT PRIVILEGES FOR ROLE dump_test' => {
+		create_order => 14,
+		create_sql => 'ALTER DEFAULT PRIVILEGES
+					   FOR ROLE dump_test IN SCHEMA dump_test
+					   GRANT SELECT ON TABLES TO dump_test;',
+		regexp => qr/^
+			\QALTER DEFAULT PRIVILEGES \E
+			\QFOR ROLE dump_test IN SCHEMA dump_test \E
+			\QGRANT SELECT ON TABLES  TO dump_test;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			no_privs => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_pre_data => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER ROLE dump_test' => {
+		regexp => qr/^
+			\QALTER ROLE dump_test WITH \E
+			\QNOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN \E
+			\QNOREPLICATION NOBYPASSRLS;\E
+			$/xm,
+		like => {
+			pg_dumpall_globals => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER FUNCTION dump_test.pltestlang_call_handler() OWNER TO' => {
+		regexp => qr/^
+			\QALTER FUNCTION dump_test.pltestlang_call_handler() \E
+			\QOWNER TO \E
+			.*;$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO' => {
+		regexp => qr/^ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER SCHEMA dump_test OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER SCHEMA dump_test_second_schema OWNER TO' => {
+		regexp => qr/^ALTER SCHEMA dump_test_second_schema OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'ALTER TABLE ONLY test_table ADD CONSTRAINT ... PRIMARY KEY' => {
+		regexp => qr/^
+			\QALTER TABLE ONLY test_table\E \n^\s+
+			\QADD CONSTRAINT test_table_pkey PRIMARY KEY (col1);\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_pre_data => 1,
+			section_data => 1,
+		},
+	},
+	'ALTER TABLE test_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_table ENABLE ROW LEVEL SECURITY' => {
+		create_order => 23,
+		create_sql => 'ALTER TABLE dump_test.test_table
+					   ENABLE ROW LEVEL SECURITY;',
+		regexp => qr/^ALTER TABLE test_table ENABLE ROW LEVEL SECURITY;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_second_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_second_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'ALTER TABLE test_third_table OWNER TO' => {
+		regexp => qr/^ALTER TABLE test_third_table OWNER TO .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	# catch-all for ALTER ... OWNER (except LARGE OBJECTs)
+	'ALTER ... OWNER commands (except LARGE OBJECTs)' => {
+		regexp => qr/^ALTER (?!LARGE OBJECT)(.*) OWNER TO .*;$/m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			section_data => 1,
+		},
+	},
+	# catch-all for ALTER ... OWNER
+	'ALTER ... OWNER commands' => {
+		regexp => qr/^ALTER .* OWNER TO .*;$/m,
+		like => { }, # use more-specific options above
+		unlike => {
+			no_owner => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'BLOB load (contents are of test_table)' => {
+		create_order => 14,
+		create_sql =>
+		    "\\o '$tempdir/large_object_test.sql'\n"
+		  . "table dump_test.test_table;\n"
+		  . "\\o\n"
+		  . "\\lo_import '$tempdir/large_object_test.sql'\n",
+		regexp => qr/^
+			\QSELECT pg_catalog.lo_open\E \('\d+',\ \d+\);\n
+			\QSELECT pg_catalog.lowrite(0, \E
+			\Q'\x310a320a330a340a350a360a370a380a390a');\E\n
+			\QSELECT pg_catalog.lo_close(0);\E
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+	},
+	'COMMENT ON DATABASE postgres' => {
+		regexp => qr/^COMMENT ON DATABASE postgres IS .*;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT ON EXTENSION plpgsql' => {
+		regexp => qr/^COMMENT ON EXTENSION plpgsql IS .*;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COMMENT ON TABLE dump_test.test_table' => {
+		create_order => 36,
+		create_sql => 'COMMENT ON TABLE dump_test.test_table
+					   IS \'comment on table\';',
+		regexp => qr/^COMMENT ON TABLE test_table IS 'comment on table';$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'COMMENT ON COLUMN dump_test.test_table.col1' => {
+		create_order => 36,
+		create_sql => 'COMMENT ON COLUMN dump_test.test_table.col1
+					   IS \'comment on column\';',
+		regexp => qr/^
+			\QCOMMENT ON COLUMN test_table.col1 IS 'comment on column';\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+		},
+	},
+	'COMMENT ON COLUMN dump_test.composite.f1' => {
+		create_order => 44,
+		create_sql => 'COMMENT ON COLUMN dump_test.composite.f1
+					   IS \'comment on column of type\';',
+		regexp => qr/^
+			\QCOMMENT ON COLUMN composite.f1 IS 'comment on column of type';\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	# catch-all for COMMENTs
+	'COMMENT commands' => {
+		regexp => qr/^COMMENT ON /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			pg_dumpall_globals => 1,
+			section_data => 1,
+			section_post_data => 1,
+		},
+	},
+	'COPY test_table' => {
+		create_order => 4,
+		create_sql =>
+		    'INSERT INTO dump_test.test_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,9);',
+		regexp => qr/^
+			\QCOPY test_table (col1) FROM stdin;\E
+			\n(?:\d\n){9}\\\.\n
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+		},
+	},
+	'COPY fk_reference_test_table' => {
+		create_order => 22,
+		create_sql =>
+		    'INSERT INTO dump_test.fk_reference_test_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,5);',
+		regexp => qr/^
+			\QCOPY fk_reference_test_table (col1) FROM stdin;\E
+			\n(?:\d\n){5}\\\.\n
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY fk_reference_test_table second' => {
+		regexp => qr/^
+			\QCOPY test_table (col1) FROM stdin;\E
+			\n(?:\d\n){9}\\\.\n.*
+			\QCOPY fk_reference_test_table (col1) FROM stdin;\E
+			\n(?:\d\n){5}\\\.\n
+			$/xms,
+		like => {
+			data_only => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+		},
+	},
+	'COPY test_second_table' => {
+		create_order => 7,
+		create_sql =>
+		    'INSERT INTO dump_test.test_second_table (col1, col2) '
+		  . 'SELECT generate_series, generate_series::text '
+		  . 'FROM generate_series(1,9);',
+		regexp => qr/^
+			\QCOPY test_second_table (col1, col2) FROM stdin;\E
+			\n(?:\d\t\d\n){9}\\\.\n
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			section_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+		},
+	},
+	'COPY test_third_table' => {
+		create_order => 12,
+		create_sql =>
+			'INSERT INTO dump_test_second_schema.test_third_table (col1) '
+		  . 'SELECT generate_series FROM generate_series(1,9);',
+		regexp => qr/^
+			\QCOPY test_third_table (col1) FROM stdin;\E
+			\n(?:\d\n){9}\\\.\n
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_table' => {
+		regexp => qr/^
+			(?:INSERT\ INTO\ test_table\ \(col1\)\ VALUES\ \(\d\);\n){9}
+			$/xm,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_second_table' => {
+		regexp => qr/^
+			(?:INSERT\ INTO\ test_second_table\ \(col1,\ col2\)
+			   \ VALUES\ \(\d,\ '\d'\);\n){9}$/xm,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'INSERT INTO test_third_table' => {
+		regexp => qr/^
+			(?:INSERT\ INTO\ test_third_table\ \(col1\)
+			   \ VALUES\ \(\d\);\n){9}$/xm,
+		like => {
+			column_inserts => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			section_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'COPY ... commands' => { # catch-all for COPY
+		regexp => qr/^COPY /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			binary_upgrade => 1,
+			column_inserts => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE ROLE dump_test' => {
+		create_order => 1,
+		create_sql => 'CREATE ROLE dump_test;',
+		regexp => qr/^CREATE ROLE dump_test;$/m,
+		like => {
+			pg_dumpall_globals => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE DATABASE postgres' => {
+		regexp => qr/^
+			\QCREATE DATABASE postgres WITH TEMPLATE = template0 \E
+			.*;$/xm,
+		like => {
+			createdb => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE EXTENSION ... plpgsql' => {
+		regexp => qr/^
+			\QCREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\E
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE AGGREGATE dump_test.newavg' => {
+		create_order => 25,
+		create_sql => 'CREATE AGGREGATE dump_test.newavg (
+						  sfunc = int4_avg_accum,
+						  basetype = int4,
+						  stype = _int8,
+						  finalfunc = int8_avg,
+						  initcond1 = \'{0,0}\'
+					   );',
+		regexp => qr/^
+			\QCREATE AGGREGATE newavg(integer) (\E
+			\n\s+\QSFUNC = int4_avg_accum,\E
+			\n\s+\QSTYPE = bigint[],\E
+			\n\s+\QINITCOND = '{0,0}',\E
+			\n\s+\QFINALFUNC = int8_avg\E
+			\n\);$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE DOMAIN dump_test.us_postal_code' => {
+		create_order => 29,
+		create_sql => 'CREATE DOMAIN dump_test.us_postal_code AS TEXT
+					   CHECK(VALUE ~ \'^\d{5}$\' OR
+					   		 VALUE ~ \'^\d{5}-\d{4}$\');',
+		regexp => qr/^
+			\QCREATE DOMAIN us_postal_code AS text\E
+			\n\s+
+			\QCONSTRAINT us_postal_code_check CHECK \E
+			\Q(((VALUE ~ '^\d{5}\E
+			\$\Q'::text) OR (VALUE ~ '^\d{5}-\d{4}\E\$
+			\Q'::text)));\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.pltestlang_call_handler' => {
+		create_order => 17,
+		create_sql => 'CREATE FUNCTION dump_test.pltestlang_call_handler()
+					   RETURNS LANGUAGE_HANDLER AS \'$libdir/plpgsql\',
+					   \'plpgsql_call_handler\' LANGUAGE C;',
+		regexp => qr/^
+			\QCREATE FUNCTION pltestlang_call_handler() \E
+			\QRETURNS language_handler\E
+			\n\s+\QLANGUAGE c\E
+			\n\s+AS\ \'\$
+			\Qlibdir\/plpgsql', 'plpgsql_call_handler';\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.trigger_func' => {
+		create_order => 30,
+		create_sql => 'CREATE FUNCTION dump_test.trigger_func()
+					   RETURNS trigger LANGUAGE plpgsql
+					   AS $$ BEGIN RETURN NULL; END;$$;',
+		regexp => qr/^
+			\QCREATE FUNCTION trigger_func() RETURNS trigger\E
+			\n\s+\QLANGUAGE plpgsql\E
+			\n\s+AS\ \$\$
+			\Q BEGIN RETURN NULL; END;\E
+			\$\$;$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.event_trigger_func' => {
+		create_order => 32,
+		create_sql => 'CREATE FUNCTION dump_test.event_trigger_func()
+					   RETURNS event_trigger LANGUAGE plpgsql
+					   AS $$ BEGIN RETURN; END;$$;',
+		regexp => qr/^
+			\QCREATE FUNCTION event_trigger_func() RETURNS event_trigger\E
+			\n\s+\QLANGUAGE plpgsql\E
+			\n\s+AS\ \$\$
+			\Q BEGIN RETURN; END;\E
+			\$\$;$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE EVENT TRIGGER test_event_trigger' => {
+		create_order => 33,
+		create_sql => 'CREATE EVENT TRIGGER test_event_trigger
+					   ON ddl_command_start
+					   EXECUTE PROCEDURE dump_test.event_trigger_func();',
+		regexp => qr/^
+			\QCREATE EVENT TRIGGER test_event_trigger \E
+			\QON ddl_command_start\E
+			\n\s+\QEXECUTE PROCEDURE dump_test.event_trigger_func();\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE TRIGGER test_trigger' => {
+		create_order => 31,
+		create_sql => 'CREATE TRIGGER test_trigger
+					   BEFORE INSERT ON dump_test.test_table
+					   FOR EACH ROW WHEN (NEW.col1 > 10)
+					   EXECUTE PROCEDURE dump_test.trigger_func();',
+		regexp => qr/^
+			\QCREATE TRIGGER test_trigger BEFORE INSERT ON test_table \E
+			\QFOR EACH ROW WHEN ((new.col1 > 10)) \E
+			\QEXECUTE PROCEDURE trigger_func();\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE TYPE dump_test.planets AS ENUM' => {
+		create_order => 37,
+		create_sql => 'CREATE TYPE dump_test.planets
+					   AS ENUM ( \'venus\', \'earth\', \'mars\' );',
+		regexp => qr/^
+			\QCREATE TYPE planets AS ENUM (\E
+			\n\s+'venus',
+			\n\s+'earth',
+			\n\s+'mars'
+			\n\);$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.planets AS ENUM pg_upgrade' => {
+		regexp => qr/^
+			\QCREATE TYPE planets AS ENUM (\E
+			\n\);.*^
+			\QALTER TYPE dump_test.planets ADD VALUE 'venus';\E
+			\n.*^
+			\QALTER TYPE dump_test.planets ADD VALUE 'earth';\E
+			\n.*^
+			\QALTER TYPE dump_test.planets ADD VALUE 'mars';\E
+			\n$/xms,
+		like => {
+			binary_upgrade => 1,
+		},
+		unlike => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.textrange AS RANGE' => {
+		create_order => 38,
+		create_sql => 'CREATE TYPE dump_test.textrange
+					   AS RANGE (subtype=text, collation="C");',
+		regexp => qr/^
+			\QCREATE TYPE textrange AS RANGE (\E
+			\n\s+\Qsubtype = text,\E
+			\n\s+\Qcollation = pg_catalog."C"\E
+			\n\);/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.int42' => {
+		create_order => 39,
+		create_sql => 'CREATE TYPE dump_test.int42;',
+		regexp => qr/^CREATE TYPE int42;/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.int42_in' => {
+		create_order => 40,
+		create_sql => 'CREATE FUNCTION dump_test.int42_in(cstring)
+					   RETURNS dump_test.int42 AS \'int4in\'
+					   LANGUAGE internal STRICT IMMUTABLE;',
+		regexp => qr/^
+			\QCREATE FUNCTION int42_in(cstring) RETURNS int42\E
+			\n\s+\QLANGUAGE internal IMMUTABLE STRICT\E
+			\n\s+AS\ \$\$int4in\$\$;
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FUNCTION dump_test.int42_out' => {
+		create_order => 41,
+		create_sql => 'CREATE FUNCTION dump_test.int42_out(dump_test.int42)
+					   RETURNS cstring AS \'int4out\'
+					   LANGUAGE internal STRICT IMMUTABLE;',
+		regexp => qr/^
+			\QCREATE FUNCTION int42_out(int42) RETURNS cstring\E
+			\n\s+\QLANGUAGE internal IMMUTABLE STRICT\E
+			\n\s+AS\ \$\$int4out\$\$;
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.int42 populated' => {
+		create_order => 42,
+		create_sql => 'CREATE TYPE dump_test.int42 (
+						   internallength = 4,
+						   input = dump_test.int42_in,
+						   output = dump_test.int42_out,
+						   alignment = int4,
+						   default = 42,
+						   passedbyvalue);',
+		regexp => qr/^
+			\QCREATE TYPE int42 (\E
+			\n\s+\QINTERNALLENGTH = 4,\E
+			\n\s+\QINPUT = int42_in,\E
+			\n\s+\QOUTPUT = int42_out,\E
+			\n\s+\QDEFAULT = '42',\E
+			\n\s+\QALIGNMENT = int4,\E
+			\n\s+\QSTORAGE = plain,\E
+			\n\s+PASSEDBYVALUE\n\);
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TYPE dump_test.composite' => {
+		create_order => 43,
+		create_sql => 'CREATE TYPE dump_test.composite AS (
+						   f1 int,
+						   f2 dump_test.int42
+					   );',
+		regexp => qr/^
+			\QCREATE TYPE composite AS (\E
+			\n\s+\Qf1 integer,\E
+			\n\s+\Qf2 int42\E
+			\n\);
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE FOREIGN DATA WRAPPER dummy' => {
+		create_order => 35,
+		create_sql => 'CREATE FOREIGN DATA WRAPPER dummy;',
+		regexp => qr/CREATE FOREIGN DATA WRAPPER dummy;/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy' => {
+		create_order => 36,
+		create_sql => 'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;',
+		regexp => qr/CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+#######################################
+# Currently broken.
+#######################################
+#
+#	'CREATE TRANSFORM FOR int' => {
+#		create_order => 34,
+#		create_sql => 'CREATE TRANSFORM FOR int LANGUAGE SQL (FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal));',
+#		regexp => qr/CREATE TRANSFORM FOR int LANGUAGE SQL \(FROM SQL WITH FUNCTION varchar_transform\(internal\), TO SQL WITH FUNCTION int4recv\(internal\)\);/m,
+#		like => {
+#			binary_upgrade => 1,
+#			clean => 1,
+#			clean_if_exists => 1,
+#			createdb => 1,
+#			defaults => 1,
+#			exclude_dump_test_schema => 1,
+#			exclude_test_table => 1,
+#			exclude_test_table_data => 1,
+#			no_privs => 1,
+#			no_owner => 1,
+#			schema_only => 1,
+#			section_post_data => 1,
+#		},
+#		unlike => {
+#			section_pre_data => 1,
+#			only_dump_test_schema => 1,
+#			only_dump_test_table => 1,
+#			pg_dumpall_globals => 1,
+#			test_schema_plus_blobs => 1,
+#		},
+#	},
+	'CREATE LANGUAGE pltestlang' => {
+		create_order => 18,
+		create_sql => 'CREATE LANGUAGE pltestlang
+					   HANDLER dump_test.pltestlang_call_handler;',
+		regexp => qr/^
+			\QCREATE PROCEDURAL LANGUAGE pltestlang \E
+			\QHANDLER pltestlang_call_handler;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE MATERIALIZED VIEW matview' => {
+		create_order => 20,
+		create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview (col1) AS
+					   SELECT * FROM dump_test.test_table;',
+		regexp => qr/^
+			\QCREATE MATERIALIZED VIEW matview AS\E
+			\n\s+\QSELECT test_table.col1\E
+			\n\s+\QFROM test_table\E
+			\n\s+\QWITH NO DATA;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE MATERIALIZED VIEW matview_second' => {
+		create_order => 21,
+		create_sql => 'CREATE MATERIALIZED VIEW
+						   dump_test.matview_second (col1) AS
+						   SELECT * FROM dump_test.matview;',
+		regexp => qr/^
+			\QCREATE MATERIALIZED VIEW matview_second AS\E
+			\n\s+\QSELECT matview.col1\E
+			\n\s+\QFROM matview\E
+			\n\s+\QWITH NO DATA;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE POLICY p1 ON test_table' => {
+		create_order => 22,
+		create_sql => 'CREATE POLICY p1 ON dump_test.test_table
+						   USING (true)
+						   WITH CHECK (true);',
+		regexp => qr/^
+			\QCREATE POLICY p1 ON test_table FOR ALL TO PUBLIC \E
+			\QUSING (true) WITH CHECK (true);\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p2 ON test_table FOR SELECT' => {
+		create_order => 24,
+		create_sql => 'CREATE POLICY p2 ON dump_test.test_table
+						   FOR SELECT TO dump_test USING (true);',
+		regexp => qr/^
+			\QCREATE POLICY p2 ON test_table FOR SELECT TO dump_test \E
+			\QUSING (true);\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p3 ON test_table FOR INSERT' => {
+		create_order => 25,
+		create_sql => 'CREATE POLICY p3 ON dump_test.test_table
+						   FOR INSERT TO dump_test WITH CHECK (true);',
+		regexp => qr/^
+			\QCREATE POLICY p3 ON test_table FOR INSERT \E
+			\QTO dump_test WITH CHECK (true);\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p4 ON test_table FOR UPDATE' => {
+		create_order => 26,
+		create_sql => 'CREATE POLICY p4 ON dump_test.test_table FOR UPDATE
+						   TO dump_test USING (true) WITH CHECK (true);',
+		regexp => qr/^
+			\QCREATE POLICY p4 ON test_table FOR UPDATE TO dump_test \E
+			\QUSING (true) WITH CHECK (true);\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE POLICY p5 ON test_table FOR DELETE' => {
+		create_order => 27,
+		create_sql => 'CREATE POLICY p5 ON dump_test.test_table
+						   FOR DELETE TO dump_test USING (true);',
+		regexp => qr/^
+			\QCREATE POLICY p5 ON test_table FOR DELETE \E
+			\QTO dump_test USING (true);\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			section_pre_data => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test' => {
+		create_order => 2,
+		create_sql => 'CREATE SCHEMA dump_test;',
+		regexp => qr/^CREATE SCHEMA dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE SCHEMA dump_test_second_schema' => {
+		create_order => 9,
+		create_sql => 'CREATE SCHEMA dump_test_second_schema;',
+		regexp => qr/^CREATE SCHEMA dump_test_second_schema;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE TABLE test_table' => {
+		create_order => 3,
+		create_sql => 'CREATE TABLE dump_test.test_table (
+						   col1 serial primary key,
+						   CHECK (col1 <= 1000)
+					   );',
+		regexp => qr/^
+			\QCREATE TABLE test_table (\E
+			\n\s+\Qcol1 integer NOT NULL,\E
+			\n\s+\QCONSTRAINT test_table_col1_check CHECK \E
+			\Q((col1 <= 1000))\E
+			\n\);$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE fk_reference_test_table' => {
+		create_order => 21,
+		create_sql => 'CREATE TABLE dump_test.fk_reference_test_table (
+						   col1 int primary key references dump_test.test_table
+					   );',
+		regexp => qr/^
+			\QCREATE TABLE fk_reference_test_table (\E
+			\n\s+\Qcol1 integer NOT NULL\E
+			\n\);
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE test_second_table' => {
+		create_order => 6,
+		create_sql => 'CREATE TABLE dump_test.test_second_table (
+						   col1 int,
+						   col2 text
+					   );',
+		regexp => qr/^
+			\QCREATE TABLE test_second_table (\E
+			\n\s+\Qcol1 integer,\E
+			\n\s+\Qcol2 text\E
+			\n\);
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE TABLE test_third_table' => {
+		create_order => 11,
+		create_sql => 'CREATE TABLE dump_test_second_schema.test_third_table (
+						   col1 serial
+					   );',
+		regexp => qr/^
+			\QCREATE TABLE test_third_table (\E
+			\n\s+\Qcol1 integer NOT NULL\E
+			\n\);
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE SEQUENCE test_table_col1_seq' => {
+		regexp => qr/^
+			\QCREATE SEQUENCE test_table_col1_seq\E
+			\n\s+\QSTART WITH 1\E
+			\n\s+\QINCREMENT BY 1\E
+			\n\s+\QNO MINVALUE\E
+			\n\s+\QNO MAXVALUE\E
+			\n\s+\QCACHE 1;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'CREATE SEQUENCE test_third_table_col1_seq' => {
+		regexp => qr/^
+			\QCREATE SEQUENCE test_third_table_col1_seq\E
+			\n\s+\QSTART WITH 1\E
+			\n\s+\QINCREMENT BY 1\E
+			\n\s+\QNO MINVALUE\E
+			\n\s+\QNO MAXVALUE\E
+			\n\s+\QCACHE 1;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE UNIQUE INDEX test_third_table_idx ON test_third_table' => {
+		create_order => 13,
+		create_sql => 'CREATE UNIQUE INDEX test_third_table_idx
+					   ON dump_test_second_schema.test_third_table (col1);',
+		regexp => qr/^
+			\QCREATE UNIQUE INDEX test_third_table_idx \E
+			\QON test_third_table USING btree (col1);\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'CREATE ... commands' => { # catch-all for CREATE
+		regexp => qr/^CREATE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			section_data => 1,
+		},
+	},
+	'DROP EXTENSION plpgsql' => {
+		regexp => qr/^DROP EXTENSION plpgsql;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP FUNCTION dump_test.pltestlang_call_handler()' => {
+		regexp => qr/^DROP FUNCTION dump_test\.pltestlang_call_handler\(\);$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP LANGUAGE pltestlang' => {
+		regexp => qr/^DROP PROCEDURAL LANGUAGE pltestlang;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test' => {
+		regexp => qr/^DROP SCHEMA dump_test;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP SCHEMA dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA dump_test_second_schema;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE fk_reference_test_table' => {
+		regexp => qr/^DROP TABLE dump_test\.fk_reference_test_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_second_table' => {
+		regexp => qr/^DROP TABLE dump_test\.test_second_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP TABLE test_third_table' => {
+		regexp => qr/^DROP TABLE dump_test_second_schema\.test_third_table;$/m,
+		like => {
+			clean => 1,
+		},
+		unlike => {
+			clean_if_exists => 1,
+		},
+	},
+	'DROP EXTENSION IF EXISTS plpgsql' => {
+		regexp => qr/^DROP EXTENSION IF EXISTS plpgsql;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler()' => {
+		regexp => qr/^
+			\QDROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler();\E
+			$/xm,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP LANGUAGE IF EXISTS pltestlang' => {
+		regexp => qr/^DROP PROCEDURAL LANGUAGE IF EXISTS pltestlang;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP SCHEMA IF EXISTS dump_test_second_schema' => {
+		regexp => qr/^DROP SCHEMA IF EXISTS dump_test_second_schema;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_second_table' => {
+		regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_second_table;$/m,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP TABLE IF EXISTS test_third_table' => {
+		regexp => qr/^
+			\QDROP TABLE IF EXISTS dump_test_second_schema.test_third_table;\E
+			$/xm,
+		like => {
+			clean_if_exists => 1,
+		},
+		unlike => {
+			clean => 1,
+		},
+	},
+	'DROP ... commands' => { # catch-all for DROP
+		regexp => qr/^DROP /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			binary_upgrade => 1,
+			column_inserts => 1,
+			createdb => 1,
+			data_only => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+		},
+	},
+	'GRANT USAGE ON SCHEMA dump_test_second_schema' => {
+		create_order => 10,
+		create_sql => 'GRANT USAGE ON SCHEMA dump_test_second_schema
+						   TO dump_test;',
+		regexp => qr/^
+			\QGRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT SELECT ON TABLE test_table' => {
+		create_order => 5,
+		create_sql => 'GRANT SELECT ON TABLE dump_test.test_table
+						   TO dump_test;',
+		regexp => qr/^GRANT SELECT ON TABLE test_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'GRANT SELECT ON TABLE test_third_table' => {
+		create_order => 19,
+		create_sql => 'GRANT SELECT ON
+						   TABLE dump_test_second_schema.test_third_table
+						   TO dump_test;',
+		regexp => qr/^GRANT SELECT ON TABLE test_third_table TO dump_test;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT ALL ON SEQUENCE test_third_table_col1_seq' => {
+		create_order => 28,
+		create_sql => 'GRANT ALL ON SEQUENCE
+						   dump_test_second_schema.test_third_table_col1_seq
+						   TO dump_test;',
+		regexp => qr/^
+			\QGRANT ALL ON SEQUENCE test_third_table_col1_seq TO dump_test;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT INSERT(col1) ON TABLE test_second_table' => {
+		create_order => 8,
+		create_sql => 'GRANT INSERT (col1) ON TABLE dump_test.test_second_table
+						   TO dump_test;',
+		regexp => qr/^
+			\QGRANT INSERT(col1) ON TABLE test_second_table TO dump_test;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+			test_schema_plus_blobs => 1,
+		},
+		unlike => {
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+	'GRANT EXECUTE ON FUNCTION pg_sleep() TO dump_test' => {
+		create_order => 16,
+		create_sql => 'GRANT EXECUTE ON FUNCTION pg_sleep(float8)
+						   TO dump_test;',
+		regexp => qr/^
+			\QGRANT ALL ON FUNCTION pg_sleep(double precision) TO dump_test;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT SELECT (proname ...) ON TABLE pg_proc TO public' => {
+		create_order => 46,
+		create_sql => 'GRANT SELECT (
+						   tableoid,
+						   oid,
+						   proname,
+						   pronamespace,
+						   proowner,
+						   prolang,
+						   procost,
+						   prorows,
+						   provariadic,
+						   protransform,
+						   proisagg,
+						   proiswindow,
+						   prosecdef,
+						   proleakproof,
+						   proisstrict,
+						   proretset,
+						   provolatile,
+						   proparallel,
+						   pronargs,
+						   pronargdefaults,
+						   prorettype,
+						   proargtypes,
+						   proallargtypes,
+						   proargmodes,
+						   proargnames,
+						   proargdefaults,
+						   protrftypes,
+						   prosrc,
+						   probin,
+						   proconfig,
+						   proacl
+						) ON TABLE pg_proc TO public;',
+		regexp => qr/
+		\QGRANT SELECT(tableoid) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(oid) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proname) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(pronamespace) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proowner) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(prolang) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(procost) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(prorows) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(provariadic) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(protransform) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proisagg) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proiswindow) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(prosecdef) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proleakproof) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proisstrict) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proretset) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(provolatile) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proparallel) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(pronargs) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(pronargdefaults) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(prorettype) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proargtypes) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proallargtypes) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proargmodes) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proargnames) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proargdefaults) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(protrftypes) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(prosrc) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(probin) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proconfig) ON TABLE pg_proc TO PUBLIC;\E\n.*
+		\QGRANT SELECT(proacl) ON TABLE pg_proc TO PUBLIC;\E$/xms,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'GRANT commands' => { # catch-all for GRANT commands
+		regexp => qr/^GRANT /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			no_privs => 1,
+			section_data => 1,
+		},
+	},
+	'REFRESH MATERIALIZED VIEW matview' => {
+		regexp => qr/^REFRESH MATERIALIZED VIEW matview;$/m,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+	},
+	'REFRESH MATERIALIZED VIEW matview_second' => {
+		regexp => qr/^
+			\QREFRESH MATERIALIZED VIEW matview;\E
+			\n.*
+			\QREFRESH MATERIALIZED VIEW matview_second;\E
+			$/xms,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_privs => 1,
+			no_owner => 1,
+			only_dump_test_schema => 1,
+			test_schema_plus_blobs => 1,
+			section_post_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			exclude_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			pg_dumpall_globals => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+	},
+	'REVOKE EXECUTE ON FUNCTION pg_sleep() FROM public' => {
+		create_order => 15,
+		create_sql => 'REVOKE EXECUTE ON FUNCTION pg_sleep(float8)
+						   FROM public;',
+		regexp => qr/^
+			\QREVOKE ALL ON FUNCTION pg_sleep(double precision) FROM PUBLIC;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE SELECT ON TABLE pg_proc FROM public' => {
+		create_order => 45,
+		create_sql => 'REVOKE SELECT ON TABLE pg_proc FROM public;',
+		regexp => qr/^REVOKE SELECT ON TABLE pg_proc FROM PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE CREATE ON SCHEMA public FROM public' => {
+		create_order => 16,
+		create_sql => 'REVOKE CREATE ON SCHEMA public FROM public;',
+		regexp => qr/^
+			\QREVOKE ALL ON SCHEMA public FROM PUBLIC;\E
+			\n\QGRANT USAGE ON SCHEMA public TO PUBLIC;\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE USAGE ON LANGUAGE plpgsql FROM public' => {
+		create_order => 16,
+		create_sql => 'REVOKE USAGE ON LANGUAGE plpgsql FROM public;',
+		regexp => qr/^REVOKE ALL ON LANGUAGE plpgsql FROM PUBLIC;$/m,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			exclude_dump_test_schema => 1,
+			exclude_test_table => 1,
+			exclude_test_table_data => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			only_dump_test_schema => 1,
+			only_dump_test_table => 1,
+			test_schema_plus_blobs => 1,
+		},
+	},
+	'REVOKE commands' => { # catch-all for REVOKE commands
+		regexp => qr/^REVOKE /m,
+		like => { }, # use more-specific options above
+		unlike => {
+			column_inserts => 1,
+			data_only => 1,
+			no_privs => 1,
+			pg_dumpall_globals => 1,
+		},
+	},
+);
+
+#########################################
+# Create a PG instance to test actually dumping from
+
+my $node = get_new_node('main');
+$node->init;
+$node->start;
+
+my $port = $node->port;
+
+# Start with 2 because of command_exit_is() tests below
+my $num_tests = 2;
+
+foreach my $run (sort keys %pgdump_runs) {
+	my $test_key = $run;
+
+	# Each run of pg_dump is a test itself
+	$num_tests++;
+
+	# If there is a restore cmd, that's another test
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$num_tests++;
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	# Then count all the tests run against each run
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			$num_tests++;
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			$num_tests++;
+		}
+	}
+}
+plan tests => $num_tests;
+
+#########################################
+# Set up schemas, tables, etc, to be dumped.
+
+# Build up the create statements
+my $create_sql = '';
+
+foreach my $test (
+	sort {
+		if ($tests{$a}->{create_order} and $tests{$b}->{create_order}) {
+			$tests{$a}->{create_order} <=> $tests{$b}->{create_order};
+		} elsif ($tests{$a}->{create_order}) {
+			-1;
+		} elsif ($tests{$b}->{create_order}) {
+			1;
+		} else {
+			0;
+		}
+	} keys %tests) {
+	if ($tests{$test}->{create_sql}) {
+		$create_sql .= $tests{$test}->{create_sql};
+	}
+}
+
+# Send the combined set of commands to psql
+$node->safe_psql('postgres', $create_sql);
+
+#########################################
+# Test connecting to a non-existent database
+
+command_exit_is([ 'pg_dump', '-p', "$port", 'qqq' ],
+	1, 'pg_dump: [archiver (db)] connection to database "qqq" failed: FATAL:  database "qqq" does not exist');
+
+command_exit_is([ 'pg_dump', '-p', "$port", '--role=dump_test' ],
+	1, 'pg_dump: [archiver (db)] query failed: ERROR:  permission denied for');
+
+#########################################
+# Run all runs
+
+foreach my $run (sort keys %pgdump_runs) {
+
+	my $test_key = $run;
+
+	$node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs");
+
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$node->command_ok(\@{ $pgdump_runs{$run}->{restore_cmd} }, "$run: pg_restore runs");
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	my $output_file = slurp_file("$tempdir/${run}.sql");
+
+	#########################################
+	# Run all tests where this run is included
+	# as either a 'like' or 'unlike' test.
+
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			like($output_file, $tests{$test}->{regexp}, "$run: dumps $test");
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			unlike($output_file, $tests{$test}->{regexp}, "$run: does not dump $test");
+		}
+	}
+}
+
+#########################################
+# Stop the database instance, which will be removed at the end of the tests.
+
+$node->stop('fast');
diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 9b93552..8926627 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -12,6 +12,7 @@ SUBDIRS = \
 		  test_ddl_deparse \
 		  test_extensions \
 		  test_parser \
+		  test_pg_dump \
 		  test_rls_hooks \
 		  test_shm_mq \
 		  worker_spi
diff --git a/src/test/modules/test_pg_dump/.gitignore b/src/test/modules/test_pg_dump/.gitignore
new file mode 100644
index 0000000..5dcb3ff
--- /dev/null
+++ b/src/test/modules/test_pg_dump/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/src/test/modules/test_pg_dump/Makefile b/src/test/modules/test_pg_dump/Makefile
new file mode 100644
index 0000000..0eb3b5f
--- /dev/null
+++ b/src/test/modules/test_pg_dump/Makefile
@@ -0,0 +1,25 @@
+# src/test/modules/test_rls_hooks/Makefile
+
+MODULE_big = test_pg_dump
+PGFILEDESC = "test_pg_dump - Test pg_dump with an extension"
+
+EXTENSION = test_pg_dump
+DATA = test_pg_dump--1.0.sql
+
+REGRESS = test_pg_dump
+
+check: prove-check
+
+prove-check:
+	$(prove_check)
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_pg_dump
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_pg_dump/README b/src/test/modules/test_pg_dump/README
new file mode 100644
index 0000000..e6c78b8
--- /dev/null
+++ b/src/test/modules/test_pg_dump/README
@@ -0,0 +1,2 @@
+test_pg_dump is an extension explicitly to test pg_dump when
+extensions are present in the system.
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
new file mode 100644
index 0000000..360caa2
--- /dev/null
+++ b/src/test/modules/test_pg_dump/expected/test_pg_dump.out
@@ -0,0 +1,6 @@
+SELECT 1;
+ ?column? 
+----------
+        1
+(1 row)
+
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
new file mode 100644
index 0000000..e0ac49d
--- /dev/null
+++ b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql
@@ -0,0 +1 @@
+SELECT 1;
diff --git a/src/test/modules/test_pg_dump/t/001_base.pl b/src/test/modules/test_pg_dump/t/001_base.pl
new file mode 100644
index 0000000..79093aa
--- /dev/null
+++ b/src/test/modules/test_pg_dump/t/001_base.pl
@@ -0,0 +1,403 @@
+use strict;
+use warnings;
+
+use Config;
+use PostgresNode;
+use TestLib;
+use Test::More;
+
+my $tempdir       = TestLib::tempdir;
+my $tempdir_short = TestLib::tempdir_short;
+
+###############################################################
+# This structure is based off of the src/bin/pg_dump/t test
+# suite.
+###############################################################
+# Definition of the pg_dump runs to make.
+#
+# Each of these runs are named and those names are used below
+# to define how each test should (or shouldn't) treat a result
+# from a given run.
+#
+# test_key indicates that a given run should simply use the same
+# set of like/unlike tests as another run, and which run that is.
+#
+# dump_cmd is the pg_dump command to run, which is an array of
+# the full command and arguments to run.  Note that this is run
+# using $node->command_ok(), so the port does not need to be
+# specified and is pulled from $PGPORT, which is set by the
+# PostgresNode system.
+#
+# restore_cmd is the pg_restore command to run, if any.  Note
+# that this should generally be used when the pg_dump goes to
+# a non-text file and that the restore can then be used to
+# generate a text file to run through the tests from the
+# non-text file generated by pg_dump.
+#
+# TODO: Have pg_restore actually restore to an independent
+# database and then pg_dump *that* database (or something along
+# those lines) to validate that part of the process.
+
+my %pgdump_runs = (
+	binary_upgrade => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/binary_upgrade.sql",
+			'--schema-only',
+			'--binary-upgrade',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean.sql",
+			'-c',
+			'-d', 'postgres', # alternative way to specify database
+		],
+	},
+	clean_if_exists => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/clean_if_exists.sql",
+			'-c',
+			'--if-exists',
+			'-E', 'UTF8', # no-op, just tests that option is accepted
+			'postgres',
+		],
+	},
+	column_inserts => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/column_inserts.sql",
+			'-a',
+			'--column-inserts',
+			'postgres',
+		],
+	},
+	createdb => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/createdb.sql",
+			'-C',
+			'-R', # no-op, just for testing
+			'postgres',
+		],
+	},
+	data_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/data_only.sql",
+			'-a',
+			'-v', # no-op, just make sure it works
+			'postgres',
+		],
+	},
+	defaults => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/defaults.sql",
+			'postgres',
+		],
+	},
+	defaults_custom_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fc',
+			'-Z6',
+			'-f', "$tempdir/defaults_custom_format.dump",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_custom_format.sql",
+			"$tempdir/defaults_custom_format.dump",
+		],
+	},
+	defaults_dir_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-f', "$tempdir/defaults_dir_format",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_dir_format.sql",
+			"$tempdir/defaults_dir_format",
+		],
+	},
+	defaults_parallel => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Fd',
+			'-j2',
+			'-f', "$tempdir/defaults_parallel",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_parallel.sql",
+			"$tempdir/defaults_parallel",
+		],
+	},
+	defaults_tar_format => {
+		test_key => 'defaults',
+		dump_cmd => [
+			'pg_dump',
+			'-Ft',
+			'-f', "$tempdir/defaults_tar_format.tar",
+			'postgres',
+		],
+		restore_cmd => [
+			'pg_restore',
+			'-f', "$tempdir/defaults_tar_format.sql",
+			"$tempdir/defaults_tar_format.tar",
+		],
+	},
+	pg_dumpall_globals => {
+		dump_cmd => [
+			'pg_dumpall',
+			'-f', "$tempdir/pg_dumpall_globals.sql",
+			'-g',
+		],
+	},
+	no_privs => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_privs.sql",
+			'-x',
+			'postgres',
+		],
+	},
+	no_owner => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/no_owner.sql",
+			'-O',
+			'postgres',
+		],
+	},
+	schema_only => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/schema_only.sql",
+			'-s',
+			'postgres',
+		],
+	},
+	section_pre_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_pre_data.sql",
+			'--section=pre-data',
+			'postgres',
+		],
+	},
+	section_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_data.sql",
+			'--section=data',
+			'postgres',
+		],
+	},
+	section_post_data => {
+		dump_cmd => [
+			'pg_dump',
+			'-f', "$tempdir/section_post_data.sql",
+			'--section=post-data',
+			'postgres',
+		],
+	},
+);
+
+###############################################################
+# Definition of the tests to run.
+#
+# Each test is defined using the log message that will be used.
+#
+# A regexp should be defined for each test which provides the
+# basis for the test.  That regexp will be run against the output
+# file of each of the runs which the test is to be run against
+# and the success of the result will depend on if the regexp
+# result matches the expected 'like' or 'unlike' case.
+#
+# For each test, there are two sets of runs defined, one for
+# the 'like' tests and one for the 'unlike' tests.  'like'
+# essentially means "the regexp for this test must match the
+# output file".  'unlike' is the opposite.
+#
+# There are a few 'catch-all' tests which can be used to have
+# a single, simple, test to over a range of other tests.  For
+# example, there is a '^CREATE ' test, which is used for the
+# 'data-only' test as there should never be any kind of CREATE
+# statement in a 'data-only' run.  Without the catch-all, we
+# would have to list the 'data-only' run in each and every
+# 'CREATE xxxx' test, which would be a lot of additional tests.
+#
+# Note that it makes no sense for the same run to ever be listed
+# in both 'like' and 'unlike' categories.
+#
+# There can then be a 'create_sql' and 'create_order' for a
+# given test.  The 'create_sql' commands are collected up in
+# 'create_order' and then run against the database prior to any
+# of the pg_dump runs happening.  This is what "seeds" the
+# system with objects to be dumped out.
+#
+# Building of this hash takes a bit of time as all of the regexps
+# included in it are compiled.  This greatly improves performance
+# as the regexps are used for each run the test applies to.
+
+my %tests = (
+	'CREATE EXTENSION test_pg_dump' => {
+		create_order => 1,
+		create_sql => 'CREATE EXTENSION test_pg_dump;',
+		regexp => qr/^
+			\QCREATE EXTENSION IF NOT EXISTS test_pg_dump WITH SCHEMA public;\E
+			$/xm,
+		like => {
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			binary_upgrade => 1,
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+	'COMMENT ON EXTENSION test_pg_dump' => {
+		regexp => qr/^
+			\QCOMMENT ON EXTENSION test_pg_dump \E
+			\QIS 'Test pg_dump with an extension';\E
+			$/xm,
+		like => {
+			binary_upgrade => 1,
+			clean => 1,
+			clean_if_exists => 1,
+			createdb => 1,
+			defaults => 1,
+			no_privs => 1,
+			no_owner => 1,
+			schema_only => 1,
+			section_pre_data => 1,
+		},
+		unlike => {
+			pg_dumpall_globals => 1,
+			section_post_data => 1,
+		},
+	},
+);
+
+#########################################
+# Create a PG instance to test actually dumping from
+
+my $node = get_new_node('main');
+$node->init;
+$node->start;
+
+my $port = $node->port;
+
+my $num_tests = 0;
+
+foreach my $run (sort keys %pgdump_runs) {
+	my $test_key = $run;
+
+	# Each run of pg_dump is a test itself
+	$num_tests++;
+
+	# If there is a restore cmd, that's another test
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$num_tests++;
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	# Then count all the tests run against each run
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			$num_tests++;
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			$num_tests++;
+		}
+	}
+}
+plan tests => $num_tests;
+
+#########################################
+# Set up schemas, tables, etc, to be dumped.
+
+# Build up the create statements
+my $create_sql = '';
+
+foreach my $test (
+	sort {
+		if ($tests{$a}->{create_order} and $tests{$b}->{create_order}) {
+			$tests{$a}->{create_order} <=> $tests{$b}->{create_order};
+		} elsif ($tests{$a}->{create_order}) {
+			-1;
+		} elsif ($tests{$b}->{create_order}) {
+			1;
+		} else {
+			0;
+		}
+	} keys %tests) {
+	if ($tests{$test}->{create_sql}) {
+		$create_sql .= $tests{$test}->{create_sql};
+	}
+}
+
+# Send the combined set of commands to psql
+$node->safe_psql('postgres', $create_sql);
+
+#########################################
+# Run all runs
+
+foreach my $run (sort keys %pgdump_runs) {
+
+	my $test_key = $run;
+
+	$node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs");
+
+	if ($pgdump_runs{$run}->{restore_cmd}) {
+		$node->command_ok(\@{ $pgdump_runs{$run}->{restore_cmd} }, "$run: pg_restore runs");
+	}
+
+	if ($pgdump_runs{$run}->{test_key}) {
+		$test_key = $pgdump_runs{$run}->{test_key};
+	}
+
+	my $output_file = slurp_file("$tempdir/${run}.sql");
+
+	#########################################
+	# Run all tests where this run is included
+	# as either a 'like' or 'unlike' test.
+
+	foreach my $test (sort keys %tests) {
+		if ($tests{$test}->{like}->{$test_key}) {
+			like($output_file, $tests{$test}->{regexp}, "$run: dumps $test");
+		}
+
+		if ($tests{$test}->{unlike}->{$test_key}) {
+			unlike($output_file, $tests{$test}->{regexp}, "$run: does not dump $test");
+		}
+	}
+}
+
+#########################################
+# Stop the database instance, which will be removed at the end of the tests.
+
+$node->stop('fast');
diff --git a/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql
new file mode 100644
index 0000000..e8ed6da
--- /dev/null
+++ b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql
@@ -0,0 +1,8 @@
+/* src/test/modules/test_pg_dump/test_pg_dump--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_pg_dump" to load this file. \quit
+
+CREATE TABLE regress_pg_dump_table (
+	col1 int
+);
diff --git a/src/test/modules/test_pg_dump/test_pg_dump.control b/src/test/modules/test_pg_dump/test_pg_dump.control
new file mode 100644
index 0000000..fe3450d
--- /dev/null
+++ b/src/test/modules/test_pg_dump/test_pg_dump.control
@@ -0,0 +1,3 @@
+comment = 'Test pg_dump with an extension'
+default_version = '1.0'
+relocatable = true
-- 
2.5.0

#32Stephen Frost
sfrost@snowman.net
In reply to: Noah Misch (#9)
1 attachment(s)

* Noah Misch (noah@leadboat.com) wrote:

On Tue, Apr 05, 2016 at 05:50:18PM -0400, Stephen Frost wrote:

@@ -14187,18 +14869,65 @@ dumpTable(Archive *fout, TableInfo *tbinfo)

+							  "FROM pg_catalog.pg_attribute at "
+					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
+							  "LEFT JOIN pg_init_privs pip ON "

Since pg_attribute and pg_class require schema qualification here, so does
pg_init_privs. Likewise elsewhere in the patch's pg_dump changes.

Attached is a patch to qualify the tables used in that query. I
reviewed all of the other pg_init_privs uses and they all match the
qualification level of the other tables in those queries. This isn't
too surprising as this is the only query which happens outside of the
"get*()" functions.

This patch doesn't do anything but qualify the table usage and that
query is checked by the pg_dump regression suite and ran fine for me,
so, if there are no objections, I'll push this later on this afternoon.

Thanks!

Stephen

Attachments:

qualify_dumpTable_query.patchtext/x-diff; charset=us-asciiDownload
From b8032e96ad1865a824ea2feb2f2a34f9b29ac6ac Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Tue, 10 May 2016 12:55:11 -0400
Subject: [PATCH] Qualify table usage in dumpTable()

All of the other tables used in the query in dumpTable(), which is
collecting column-level ACLs, are qualified, so we should be qualifying
the pg_init_privs and related sub-select against pg_class too.

Pointed out by Noah, patch by me.
---
 src/bin/pg_dump/pg_dump.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 1267afb..4a9b1bf 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -14992,9 +14992,10 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 							  "%s AS initrattacl "
 							  "FROM pg_catalog.pg_attribute at "
 					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
-							  "LEFT JOIN pg_init_privs pip ON "
+							  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
 							  "(pip.classoid = "
-				 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
+							  "(SELECT oid FROM pg_catalog.pg_class "
+							  "WHERE relname = 'pg_class') AND "
 				   " at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
 							  "WHERE at.attrelid = '%u' AND "
 							  "NOT at.attisdropped "
-- 
2.5.0

#33Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Stephen Frost (#32)

Stephen Frost wrote:

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 1267afb..4a9b1bf 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -14992,9 +14992,10 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
"%s AS initrattacl "
"FROM pg_catalog.pg_attribute at "
"JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
-							  "LEFT JOIN pg_init_privs pip ON "
+							  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
"(pip.classoid = "
-				 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
+							  "(SELECT oid FROM pg_catalog.pg_class "
+							  "WHERE relname = 'pg_class') AND "
" at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
"WHERE at.attrelid = '%u' AND "
"NOT at.attisdropped "

The subquery comparing the OID of pg_class using only a condition on
relname seems wrong; wouldn't it fail or produce wrong results if
somebody creates a table named pg_class in another schema? I think you
should write the comparison like this instead:
classoid = 'pg_catalog.pg_class'::regclass

--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#34Stephen Frost
sfrost@snowman.net
In reply to: Alvaro Herrera (#33)

* Alvaro Herrera (alvherre@2ndquadrant.com) wrote:

Stephen Frost wrote:

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 1267afb..4a9b1bf 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -14992,9 +14992,10 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
"%s AS initrattacl "
"FROM pg_catalog.pg_attribute at "
"JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
-							  "LEFT JOIN pg_init_privs pip ON "
+							  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
"(pip.classoid = "
-				 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
+							  "(SELECT oid FROM pg_catalog.pg_class "
+							  "WHERE relname = 'pg_class') AND "
" at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
"WHERE at.attrelid = '%u' AND "
"NOT at.attisdropped "

The subquery comparing the OID of pg_class using only a condition on
relname seems wrong; wouldn't it fail or produce wrong results if
somebody creates a table named pg_class in another schema? I think you
should write the comparison like this instead:
classoid = 'pg_catalog.pg_class'::regclass

Errr, I could have sworn I was doing that, but clearly I'm not.

Will fix.

Thanks!

Stephen

#35Stephen Frost
sfrost@snowman.net
In reply to: Alvaro Herrera (#33)
1 attachment(s)

Alvaro,

* Alvaro Herrera (alvherre@2ndquadrant.com) wrote:

The subquery comparing the OID of pg_class using only a condition on
relname seems wrong; wouldn't it fail or produce wrong results if
somebody creates a table named pg_class in another schema? I think you
should write the comparison like this instead:
classoid = 'pg_catalog.pg_class'::regclass

Thanks, patch attached which does that (qualifying to the same level as
the surrounding query for each).

I've run it through my tests and will plan to push it tomorrow.

Thanks!

Stephen

Attachments:

qualify_dumpTable_query_v2.patchtext/x-diff; charset=us-asciiDownload
From e294008daa8e909059c94441643157fddf9af9b6 Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Tue, 10 May 2016 12:55:11 -0400
Subject: [PATCH] Qualify table usage in dumpTable() and use regclass

All of the other tables used in the query in dumpTable(), which is
collecting column-level ACLs, are qualified, so we should be qualifying
the pg_init_privs and related sub-select against pg_class too.

Also, use ::regclass (or ::pg_catalog.regclass, where appropriate)
instead of using a poorly constructed query to get the OID for various
catalog tables.

Issues identified by Noah and Alvaro, patch by me.
---
 src/bin/pg_dump/pg_dump.c | 59 ++++++++++++++++++++++++-----------------------
 1 file changed, 30 insertions(+), 29 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 1267afb..1d985e4 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2825,8 +2825,8 @@ getBlobs(Archive *fout)
 						  "%s AS initrlomacl "
 						  "FROM pg_largeobject_metadata l "
 						  "LEFT JOIN pg_init_privs pip ON "
-						  "(l.oid = pip.objoid AND pip.classoid = "
-				"(SELECT oid FROM pg_class WHERE relname = 'pg_largeobject')"
+						  "(l.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_largeobject'::regclass "
 						  "AND pip.objsubid = 0) ",
 						  username_subquery,
 						  acl_subquery->data,
@@ -3569,8 +3569,8 @@ getNamespaces(Archive *fout, int *numNamespaces)
 						  "%s as initrnspacl "
 						  "FROM pg_namespace n "
 						  "LEFT JOIN pg_init_privs pip "
-						  "ON (n.oid = pip.objoid AND pip.classoid = "
-				 "(SELECT oid FROM pg_class WHERE relname = 'pg_namespace') "
+						  "ON (n.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_namespace'::regclass "
 						  "AND pip.objsubid = 0) ",
 						  username_subquery,
 						  acl_subquery->data,
@@ -3851,9 +3851,9 @@ getTypes(Archive *fout, int *numTypes)
 						  "t.typname[0] = '_' AND t.typelem != 0 AND "
 						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
 						  "FROM pg_type t "
-						  "LEFT JOIN pg_init_privs pip "
-						  "ON (t.oid = pip.objoid AND pip.classoid = "
-					  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(t.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_type'::regclass "
 						  "AND pip.objsubid = 0) ",
 						  acl_subquery->data,
 						  racl_subquery->data,
@@ -4713,8 +4713,8 @@ getAggregates(Archive *fout, int *numAggs)
 						  "%s AS initraggacl "
 						  "FROM pg_proc p "
 						  "LEFT JOIN pg_init_privs pip ON "
-						  "(p.oid = pip.objoid AND pip.classoid = "
-					  "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "(p.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_proc'::regclass "
 						  "AND pip.objsubid = 0) "
 						  "WHERE p.proisagg AND ("
 						  "p.pronamespace != "
@@ -4956,8 +4956,8 @@ getFuncs(Archive *fout, int *numFuncs)
 						  "(%s p.proowner) AS rolname "
 						  "FROM pg_proc p "
 						  "LEFT JOIN pg_init_privs pip ON "
-						  "(p.oid = pip.objoid AND pip.classoid = "
-					  "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') "
+						  "(p.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_proc'::regclass "
 						  "AND pip.objsubid = 0) "
 						  "WHERE NOT proisagg "
 						  "AND NOT EXISTS (SELECT 1 FROM pg_depend "
@@ -5246,9 +5246,10 @@ getTables(Archive *fout, int *numTables)
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
 						  "tc.reloptions AS toast_reloptions, "
-						  "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON"
-						  "(c.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND pip.objsubid = at.attnum)"
+						  "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
+						  "(c.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_class'::regclass "
+						  "AND pip.objsubid = at.attnum)"
 						  "WHERE at.attrelid = c.oid AND ("
 						  "%s IS NOT NULL "
 						  "OR %s IS NOT NULL "
@@ -5264,9 +5265,9 @@ getTables(Archive *fout, int *numTables)
 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
 					   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
 						  "LEFT JOIN pg_init_privs pip ON "
-						  "(c.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class "
-						  "WHERE relname = 'pg_class') AND pip.objsubid = 0) "
+						  "(c.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_class'::regclass "
+						  "AND pip.objsubid = 0) "
 				   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
 						  "ORDER BY c.oid",
 						  acl_subquery->data,
@@ -7163,9 +7164,9 @@ getProcLangs(Archive *fout, int *numProcLangs)
 						  "%s AS initrlanacl, "
 						  "(%s l.lanowner) AS lanowner "
 						  "FROM pg_language l "
-						  "LEFT JOIN pg_init_privs pip "
-						  "ON (l.oid = pip.objoid AND pip.classoid = "
-					  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(l.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_type'::regclass "
 						  "AND pip.objsubid = 0) "
 						  "WHERE l.lanispl "
 						  "ORDER BY l.oid",
@@ -8583,9 +8584,9 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 						  "ORDER BY option_name"
 						  "), E',\n    ') AS fdwoptions "
 						  "FROM pg_foreign_data_wrapper f "
-						  "LEFT JOIN pg_init_privs pip "
-						  "ON (f.oid = pip.objoid AND pip.classoid = "
-						  "(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_data_wrapper') "
+						  "LEFT JOIN pg_init_privs pip ON "
+						  "(f.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
 						  "AND pip.objsubid = 0) ",
 						  username_subquery,
 						  acl_subquery->data,
@@ -8753,8 +8754,8 @@ getForeignServers(Archive *fout, int *numForeignServers)
 						  "), E',\n    ') AS srvoptions "
 						  "FROM pg_foreign_server f "
 						  "LEFT JOIN pg_init_privs pip "
-						  "ON (f.oid = pip.objoid AND pip.classoid = "
-			"(SELECT oid FROM pg_class WHERE relname = 'pg_foreign_server') "
+						  "ON (f.oid = pip.objoid "
+						  "AND pip.classoid = 'pg_foreign_server'::regclass "
 						  "AND pip.objsubid = 0) ",
 						  username_subquery,
 						  acl_subquery->data,
@@ -14992,10 +14993,10 @@ dumpTable(Archive *fout, TableInfo *tbinfo)
 							  "%s AS initrattacl "
 							  "FROM pg_catalog.pg_attribute at "
 					   "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
-							  "LEFT JOIN pg_init_privs pip ON "
-							  "(pip.classoid = "
-				 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AND "
-				   " at.attrelid = pip.objoid AND at.attnum = pip.objsubid) "
+							  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
+							  "(at.attrelid = pip.objoid "
+			  "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
+							  "AND at.attnum = pip.objsubid) "
 							  "WHERE at.attrelid = '%u' AND "
 							  "NOT at.attisdropped "
 							  "AND ("
-- 
2.5.0