Re: Assorted improvements in pg_dump

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: Assorted improvements in pg_dump
Дата
Msg-id 2518220.1638567222@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: Assorted improvements in pg_dump  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers
Here's an updated version of this patch set.  The only non-line-number
changes are

(1) in 0004, I dealt with the issue of not having unnest() in old branches
by bumping the minimum remote server version to 8.4.  Seeing that we seem
to have consensus in the other thread to push the minimum up to somewhere
around 9.2, I see no point in making this patch put in conditional code
that we'd shortly rip out again.

(2) I also added some comments to 0004 to hopefully address Justin's
confusion about string lengths.

I feel quite fortunate that a month's worth of commitfest hacking
didn't break any of these patches.  Unless someone intends to
review these more thoroughly than they already have, I'd like to
go ahead and push them.

            regards, tom lane

diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index ecab0a9e4e..36f8d5682e 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -584,6 +584,8 @@ AssignDumpId(DumpableObject *dobj)
     dobj->namespace = NULL;        /* may be set later */
     dobj->dump = DUMP_COMPONENT_ALL;    /* default assumption */
     dobj->dump_contains = DUMP_COMPONENT_ALL;    /* default assumption */
+    /* All objects have definitions; we may set more components bits later */
+    dobj->components = DUMP_COMPONENT_DEFINITION;
     dobj->ext_member = false;    /* default assumption */
     dobj->depends_on_ext = false;    /* default assumption */
     dobj->dependencies = NULL;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index c590003f18..15f55cbb19 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -134,6 +134,14 @@ static const CatalogId nilCatalogId = {0, 0};
 static bool have_extra_float_digits = false;
 static int    extra_float_digits;

+/* sorted table of comments */
+static CommentItem *comments = NULL;
+static int    ncomments = 0;
+
+/* sorted table of security labels */
+static SecLabelItem *seclabels = NULL;
+static int    nseclabels = 0;
+
 /*
  * The default number of rows per INSERT when
  * --inserts is specified without --rows-per-insert
@@ -182,14 +190,14 @@ static inline void dumpComment(Archive *fout, const char *type,
                                int subid, DumpId dumpId);
 static int    findComments(Archive *fout, Oid classoid, Oid objoid,
                          CommentItem **items);
-static int    collectComments(Archive *fout, CommentItem **items);
+static void collectComments(Archive *fout);
 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
                          const char *namespace, const char *owner,
                          CatalogId catalogId, int subid, DumpId dumpId);
 static int    findSecLabels(Archive *fout, Oid classoid, Oid objoid,
                           SecLabelItem **items);
-static int    collectSecLabels(Archive *fout, SecLabelItem **items);
-static void dumpDumpableObject(Archive *fout, const DumpableObject *dobj);
+static void collectSecLabels(Archive *fout);
+static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
 static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
 static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
 static void dumpType(Archive *fout, const TypeInfo *tyinfo);
@@ -290,8 +298,9 @@ static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
                                                      Oid pg_type_oid,
                                                      bool force_array_type,
                                                      bool include_multirange_type);
-static void binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
-                                                    PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
+static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
+                                                PQExpBuffer upgrade_buffer,
+                                                const TableInfo *tbinfo);
 static void binary_upgrade_set_pg_class_oids(Archive *fout,
                                              PQExpBuffer upgrade_buffer,
                                              Oid pg_class_oid, bool is_index);
@@ -878,6 +887,14 @@ main(int argc, char **argv)
      */
     getDependencies(fout);

+    /*
+     * Collect comments and security labels, if wanted.
+     */
+    if (!dopt.no_comments)
+        collectComments(fout);
+    if (!dopt.no_security_labels)
+        collectSecLabels(fout);
+
     /* Lastly, create dummy objects to represent the section boundaries */
     boundaryObjs = createBoundaryObjects();

@@ -1631,6 +1648,13 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
+
+        /*
+         * Also, make like it has a comment even if it doesn't; this is so
+         * that we'll emit a command to drop the comment, if appropriate.
+         * (Without this, we'd not call dumpCommentExtended for it.)
+         */
+        nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
     }
     else
         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
@@ -2507,7 +2531,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
  * Make a dumpable object for the data of this specific table
  *
  * Note: we make a TableDataInfo if and only if we are going to dump the
- * table data; the "dump" flag in such objects isn't used.
+ * table data; the "dump" field in such objects isn't very interesting.
  */
 static void
 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
@@ -2567,6 +2591,9 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
     tdinfo->filtercond = NULL;    /* might get set later */
     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);

+    /* A TableDataInfo contains data, of course */
+    tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
+
     tbinfo->dataObj = tdinfo;

     /* Make sure that we'll collect per-column info for this table. */
@@ -3528,11 +3555,15 @@ getBlobs(Archive *fout)
         binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
         binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));

-        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;
+        /* Blobs have data */
+        binfo[i].dobj.components |= DUMP_COMPONENT_DATA;
+
+        /* Mark whether blob has an ACL */
+        if (!(PQgetisnull(res, i, i_lomacl) &&
+              PQgetisnull(res, i, i_rlomacl) &&
+              PQgetisnull(res, i, i_initlomacl) &&
+              PQgetisnull(res, i, i_initrlomacl)))
+            binfo[i].dobj.components |= DUMP_COMPONENT_ACL;

         /*
          * In binary-upgrade mode for blobs, we do *not* dump out the blob
@@ -3556,6 +3587,7 @@ getBlobs(Archive *fout)
         bdata->catId = nilCatalogId;
         AssignDumpId(bdata);
         bdata->name = pg_strdup("BLOBS");
+        bdata->components |= DUMP_COMPONENT_DATA;
     }

     PQclear(res);
@@ -3603,7 +3635,7 @@ dumpBlob(Archive *fout, const BlobInfo *binfo)
                      binfo->dobj.catId, 0, binfo->dobj.dumpId);

     /* Dump ACL if any */
-    if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
+    if (binfo->dobj.dump & DUMP_COMPONENT_ACL)
         dumpACL(fout, binfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
                 binfo->dobj.name, NULL,
                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
@@ -3734,6 +3766,8 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)

         if (tbinfo->rowsec)
         {
+            tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
+
             /*
              * Note: use tableoid 0 so that this object won't be mistaken for
              * something that pg_depend entries apply to.
@@ -3803,6 +3837,8 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
             if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
                 continue;

+            tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
+
             polinfo[j].dobj.objType = DO_POLICY;
             polinfo[j].dobj.catId.tableoid =
                 atooid(PQgetvalue(res, j, i_tableoid));
@@ -3855,6 +3891,7 @@ dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
     const char *cmd;
     char       *tag;

+    /* Do nothing in data-only dump */
     if (dopt->dataOnly)
         return;

@@ -3875,7 +3912,7 @@ dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
          * explicitly, because it will not match anything in pg_depend (unlike
          * the case for other PolicyInfo objects).
          */
-        if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+        if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
                                       .namespace = polinfo->dobj.namespace->dobj.name,
@@ -3937,7 +3974,7 @@ dumpPolicy(Archive *fout, const PolicyInfo *polinfo)

     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);

-    if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
+    if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
                      ARCHIVE_OPTS(.tag = tag,
                                   .namespace = polinfo->dobj.namespace->dobj.name,
@@ -4082,9 +4119,6 @@ dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
     char       *qpubname;
     bool        first = true;

-    if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
-        return;
-
     delq = createPQExpBuffer();
     query = createPQExpBuffer();

@@ -4140,13 +4174,14 @@ dumpPublication(Archive *fout, const PublicationInfo *pubinfo)

     appendPQExpBufferStr(query, ");\n");

-    ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
-                 ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
-                              .owner = pubinfo->rolname,
-                              .description = "PUBLICATION",
-                              .section = SECTION_POST_DATA,
-                              .createStmt = query->data,
-                              .dropStmt = delq->data));
+    if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+        ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
+                     ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
+                                  .owner = pubinfo->rolname,
+                                  .description = "PUBLICATION",
+                                  .section = SECTION_POST_DATA,
+                                  .createStmt = query->data,
+                                  .dropStmt = delq->data));

     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
         dumpComment(fout, "PUBLICATION", qpubname,
@@ -4387,9 +4422,6 @@ dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
     PQExpBuffer query;
     char       *tag;

-    if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
-        return;
-
     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);

     query = createPQExpBuffer();
@@ -4406,13 +4438,14 @@ dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
      * owner field anyway to ensure that the command is run by the correct
      * role at restore time.
      */
-    ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
-                 ARCHIVE_OPTS(.tag = tag,
-                              .namespace = tbinfo->dobj.namespace->dobj.name,
-                              .owner = pubinfo->rolname,
-                              .description = "PUBLICATION TABLE",
-                              .section = SECTION_POST_DATA,
-                              .createStmt = query->data));
+    if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+        ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
+                     ARCHIVE_OPTS(.tag = tag,
+                                  .namespace = tbinfo->dobj.namespace->dobj.name,
+                                  .owner = pubinfo->rolname,
+                                  .description = "PUBLICATION TABLE",
+                                  .section = SECTION_POST_DATA,
+                                  .createStmt = query->data));

     free(tag);
     destroyPQExpBuffer(query);
@@ -4582,9 +4615,6 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
     int            i;
     char        two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};

-    if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
-        return;
-
     delq = createPQExpBuffer();
     query = createPQExpBuffer();

@@ -4630,13 +4660,14 @@ dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)

     appendPQExpBufferStr(query, ");\n");

-    ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
-                 ARCHIVE_OPTS(.tag = subinfo->dobj.name,
-                              .owner = subinfo->rolname,
-                              .description = "SUBSCRIPTION",
-                              .section = SECTION_POST_DATA,
-                              .createStmt = query->data,
-                              .dropStmt = delq->data));
+    if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+        ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
+                     ARCHIVE_OPTS(.tag = subinfo->dobj.name,
+                                  .owner = subinfo->rolname,
+                                  .description = "SUBSCRIPTION",
+                                  .section = SECTION_POST_DATA,
+                                  .createStmt = query->data,
+                                  .dropStmt = delq->data));

     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
         dumpComment(fout, "SUBSCRIPTION", qsubname,
@@ -4824,30 +4855,15 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
 }

 static void
-binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
-                                        PQExpBuffer upgrade_buffer,
-                                        Oid pg_rel_oid)
+binary_upgrade_set_type_oids_by_rel(Archive *fout,
+                                    PQExpBuffer upgrade_buffer,
+                                    const TableInfo *tbinfo)
 {
-    PQExpBuffer upgrade_query = createPQExpBuffer();
-    PGresult   *upgrade_res;
-    Oid            pg_type_oid;
-
-    appendPQExpBuffer(upgrade_query,
-                      "SELECT c.reltype AS crel "
-                      "FROM pg_catalog.pg_class c "
-                      "WHERE c.oid = '%u'::pg_catalog.oid;",
-                      pg_rel_oid);
-
-    upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
-
-    pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
+    Oid            pg_type_oid = tbinfo->reltype;

     if (OidIsValid(pg_type_oid))
         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
                                                  pg_type_oid, false, false);
-
-    PQclear(upgrade_res);
-    destroyPQExpBuffer(upgrade_query);
 }

 static void
@@ -5102,18 +5118,12 @@ getNamespaces(Archive *fout, int *numNamespaces)
         /* Decide whether to dump this namespace */
         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;
+        /* Mark whether namespace has an ACL */
+        if (!(PQgetisnull(res, i, i_nspacl) &&
+              PQgetisnull(res, i, i_rnspacl) &&
+              PQgetisnull(res, i, i_initnspacl) &&
+              PQgetisnull(res, i, i_initrnspacl)))
+            nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;

         if (strlen(nsinfo[i].rolname) == 0)
             pg_log_warning("owner of schema \"%s\" appears to be invalid",
@@ -5422,11 +5432,12 @@ getTypes(Archive *fout, int *numTypes)
         /* Decide whether we want to dump it */
         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;
+        /* Mark whether type has an ACL */
+        if (!(PQgetisnull(res, i, i_typacl) &&
+              PQgetisnull(res, i, i_rtypacl) &&
+              PQgetisnull(res, i, i_inittypacl) &&
+              PQgetisnull(res, i, i_initrtypacl)))
+            tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;

         /*
          * If it's a domain, fetch info about its constraints, if any
@@ -5549,9 +5560,6 @@ 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)
             pg_log_warning("owner of operator \"%s\" appears to be invalid",
                            oprinfo[i].dobj.name);
@@ -5631,9 +5639,6 @@ 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);
@@ -5703,9 +5708,6 @@ 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);
@@ -5776,9 +5778,6 @@ 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);
@@ -5848,9 +5847,6 @@ 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 (strlen(opcinfo[i].rolname) == 0)
             pg_log_warning("owner of operator class \"%s\" appears to be invalid",
                            opcinfo[i].dobj.name);
@@ -5931,9 +5927,6 @@ 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 (strlen(opfinfo[i].rolname) == 0)
             pg_log_warning("owner of operator family \"%s\" appears to be invalid",
                            opfinfo[i].dobj.name);
@@ -6125,11 +6118,12 @@ getAggregates(Archive *fout, int *numAggs)
         /* Decide whether we want to dump it */
         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;
+        /* Mark whether aggregate has an ACL */
+        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.components |= DUMP_COMPONENT_ACL;
     }

     PQclear(res);
@@ -6355,11 +6349,12 @@ getFuncs(Archive *fout, int *numFuncs)
         /* Decide whether we want to dump it */
         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;
+        /* Mark whether function has an ACL */
+        if (!(PQgetisnull(res, i, i_proacl) &&
+              PQgetisnull(res, i, i_rproacl) &&
+              PQgetisnull(res, i, i_initproacl) &&
+              PQgetisnull(res, i, i_initrproacl)))
+            finfo[i].dobj.components |= DUMP_COMPONENT_ACL;

         if (strlen(finfo[i].rolname) == 0)
             pg_log_warning("owner of function \"%s\" appears to be invalid",
@@ -6394,6 +6389,7 @@ getTables(Archive *fout, int *numTables)
     int            i_relname;
     int            i_relnamespace;
     int            i_relkind;
+    int            i_reltype;
     int            i_rolname;
     int            i_relchecks;
     int            i_relhasindex;
@@ -6444,7 +6440,7 @@ getTables(Archive *fout, int *numTables)

     appendPQExpBuffer(query,
                       "SELECT c.tableoid, c.oid, c.relname, "
-                      "c.relnamespace, c.relkind, "
+                      "c.relnamespace, c.relkind, c.reltype, "
                       "(%s c.relowner) AS rolname, "
                       "c.relchecks, "
                       "c.relhasindex, c.relhasrules, c.relpages, "
@@ -6720,6 +6716,7 @@ getTables(Archive *fout, int *numTables)
     i_relname = PQfnumber(res, "relname");
     i_relnamespace = PQfnumber(res, "relnamespace");
     i_relkind = PQfnumber(res, "relkind");
+    i_reltype = PQfnumber(res, "reltype");
     i_rolname = PQfnumber(res, "rolname");
     i_relchecks = PQfnumber(res, "relchecks");
     i_relhasindex = PQfnumber(res, "relhasindex");
@@ -6781,6 +6778,7 @@ getTables(Archive *fout, int *numTables)
         tblinfo[i].dobj.namespace =
             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
+        tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
         tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
@@ -6843,11 +6841,30 @@ getTables(Archive *fout, int *numTables)
         else
             selectDumpableTable(&tblinfo[i], fout);

-        tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
+        /*
+         * Now, consider the table "interesting" if we need to dump its
+         * definition or its data.  Later on, we'll skip a lot of data
+         * collection for uninteresting tables.
+         *
+         * Note: the "interesting" flag will also be set by flagInhTables for
+         * parents of interesting tables, so that we collect necessary
+         * inheritance info even when the parents are not themselves being
+         * dumped.  This is the main reason why we need an "interesting" flag
+         * that's separate from the components-to-dump bitmask.
+         */
+        tblinfo[i].interesting = (tblinfo[i].dobj.dump &
+                                  (DUMP_COMPONENT_DEFINITION |
+                                   DUMP_COMPONENT_DATA)) != 0;
+
         tblinfo[i].dummy_view = false;    /* might get set during sort */
         tblinfo[i].postponed_def = false;    /* might get set during sort */

+        /* Tables have data */
+        tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
+
         /*
+         * Mark whether table has an ACL.
+         *
          * 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
@@ -6856,11 +6873,12 @@ getTables(Archive *fout, int *numTables)
          * 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;
+        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.components |= DUMP_COMPONENT_ACL;

         /*
          * Read-lock target tables to make sure they aren't DROPPED or altered
@@ -6877,10 +6895,9 @@ getTables(Archive *fout, int *numTables)
          * We only need to lock the table for certain components; see
          * pg_dump.h
          */
-        if (tblinfo[i].dobj.dump &&
+        if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
             (tblinfo[i].relkind == RELKIND_RELATION ||
-             tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE) &&
-            (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
+             tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
         {
             resetPQExpBuffer(query);
             appendPQExpBuffer(query,
@@ -7062,13 +7079,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
             continue;

         /*
-         * Ignore indexes of tables whose definitions are not to be dumped.
-         *
-         * We also need indexes on partitioned tables which have partitions to
-         * be dumped, in order to dump the indexes on the partitions.
+         * We can ignore indexes of uninteresting tables.
          */
-        if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
-            !tbinfo->interesting)
+        if (!tbinfo->interesting)
             continue;

         pg_log_info("reading indexes for table \"%s.%s\"",
@@ -7438,9 +7451,6 @@ getExtendedStatistics(Archive *fout)

         /* Decide whether we want to dump it */
         selectDumpableObject(&(statsextinfo[i].dobj), fout);
-
-        /* Stats objects do not currently have ACLs. */
-        statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
     }

     PQclear(res);
@@ -8130,9 +8140,6 @@ 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);
@@ -8309,11 +8316,12 @@ getProcLangs(Archive *fout, int *numProcLangs)
         /* Decide whether we want to dump it */
         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;
+        /* Mark whether language has an ACL */
+        if (!(PQgetisnull(res, i, i_lanacl) &&
+              PQgetisnull(res, i, i_rlanacl) &&
+              PQgetisnull(res, i, i_initlanacl) &&
+              PQgetisnull(res, i, i_initrlanacl)))
+            planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
     }

     PQclear(res);
@@ -8423,9 +8431,6 @@ 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);
@@ -9122,9 +9127,6 @@ 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);
@@ -9205,9 +9207,6 @@ 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);
@@ -9280,9 +9279,6 @@ 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);
@@ -9356,9 +9352,6 @@ 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);
@@ -9520,11 +9513,12 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
         /* Decide whether we want to dump it */
         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;
+        /* Mark whether FDW has an ACL */
+        if (!(PQgetisnull(res, i, i_fdwacl) &&
+              PQgetisnull(res, i, i_rfdwacl) &&
+              PQgetisnull(res, i, i_initfdwacl) &&
+              PQgetisnull(res, i, i_initrfdwacl)))
+            fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
     }

     PQclear(res);
@@ -9670,11 +9664,15 @@ getForeignServers(Archive *fout, int *numForeignServers)
         /* Decide whether we want to dump it */
         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;
+        /* Servers have user mappings */
+        srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
+
+        /* Mark whether server has an ACL */
+        if (!(PQgetisnull(res, i, i_srvacl) &&
+              PQgetisnull(res, i, i_rsrvacl) &&
+              PQgetisnull(res, i, i_initsrvacl) &&
+              PQgetisnull(res, i, i_initrsrvacl)))
+            srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
     }

     PQclear(res);
@@ -9826,6 +9824,9 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
         daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
         daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));

+        /* Default ACLs are ACLs, of course */
+        daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
+
         /* Decide whether we want to dump it */
         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
     }
@@ -10079,19 +10080,11 @@ static int
 findComments(Archive *fout, Oid classoid, Oid objoid,
              CommentItem **items)
 {
-    /* static storage for table of comments */
-    static CommentItem *comments = NULL;
-    static int    ncomments = -1;
-
     CommentItem *middle = NULL;
     CommentItem *low;
     CommentItem *high;
     int            nmatch;

-    /* Get comments if we didn't already */
-    if (ncomments < 0)
-        ncomments = collectComments(fout, &comments);
-
     /*
      * Do binary search to find some item matching the object.
      */
@@ -10152,15 +10145,17 @@ findComments(Archive *fout, Oid classoid, Oid objoid,
 /*
  * collectComments --
  *
- * Construct a table of all comments available for database objects.
+ * Construct a table of all comments available for database objects;
+ * also set the has-comment component flag for each relevant object.
+ *
  * We used to do per-object queries for the comments, but it's much faster
  * to pull them all over at once, and on most databases the memory cost
  * isn't high.
  *
  * The table is sorted by classoid/objid/objsubid for speed in lookup.
  */
-static int
-collectComments(Archive *fout, CommentItem **items)
+static void
+collectComments(Archive *fout)
 {
     PGresult   *res;
     PQExpBuffer query;
@@ -10170,7 +10165,7 @@ collectComments(Archive *fout, CommentItem **items)
     int            i_objsubid;
     int            ntups;
     int            i;
-    CommentItem *comments;
+    DumpableObject *dobj;

     query = createPQExpBuffer();

@@ -10190,20 +10185,52 @@ collectComments(Archive *fout, CommentItem **items)
     ntups = PQntuples(res);

     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
+    ncomments = 0;
+    dobj = NULL;

     for (i = 0; i < ntups; i++)
     {
-        comments[i].descr = PQgetvalue(res, i, i_description);
-        comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
-        comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
-        comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
+        CatalogId    objId;
+        int            subid;
+
+        objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
+        objId.oid = atooid(PQgetvalue(res, i, i_objoid));
+        subid = atoi(PQgetvalue(res, i, i_objsubid));
+
+        /* We needn't remember comments that don't match any dumpable object */
+        if (dobj == NULL ||
+            dobj->catId.tableoid != objId.tableoid ||
+            dobj->catId.oid != objId.oid)
+            dobj = findObjectByCatalogId(objId);
+        if (dobj == NULL)
+            continue;
+
+        /*
+         * Comments on columns of composite types are linked to the type's
+         * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
+         * in the type's own DumpableObject.
+         */
+        if (subid != 0 && dobj->objType == DO_TABLE &&
+            ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
+        {
+            TypeInfo   *cTypeInfo;
+
+            cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
+            if (cTypeInfo)
+                cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
+        }
+        else
+            dobj->components |= DUMP_COMPONENT_COMMENT;
+
+        comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
+        comments[ncomments].classoid = objId.tableoid;
+        comments[ncomments].objoid = objId.oid;
+        comments[ncomments].objsubid = subid;
+        ncomments++;
     }

-    /* Do NOT free the PGresult since we are keeping pointers into it */
+    PQclear(res);
     destroyPQExpBuffer(query);
-
-    *items = comments;
-    return ntups;
 }

 /*
@@ -10213,8 +10240,19 @@ collectComments(Archive *fout, CommentItem **items)
  * ArchiveEntries (TOC objects) for each object to be dumped.
  */
 static void
-dumpDumpableObject(Archive *fout, const DumpableObject *dobj)
+dumpDumpableObject(Archive *fout, DumpableObject *dobj)
 {
+    /*
+     * Clear any dump-request bits for components that don't exist for this
+     * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
+     * request for every kind of object.)
+     */
+    dobj->dump &= dobj->components;
+
+    /* Now, short-circuit if there's nothing to be done here. */
+    if (dobj->dump == 0)
+        return;
+
     switch (dobj->objType)
     {
         case DO_NAMESPACE:
@@ -10393,8 +10431,8 @@ dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
     PQExpBuffer delq;
     char       *qnspname;

-    /* Skip if not to be dumped */
-    if (!nspinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -10473,8 +10511,8 @@ dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
     PQExpBuffer delq;
     char       *qextname;

-    /* Skip if not to be dumped */
-    if (!extinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -10598,8 +10636,8 @@ dumpType(Archive *fout, const TypeInfo *tyinfo)
 {
     DumpOptions *dopt = fout->dopt;

-    /* Skip if not to be dumped */
-    if (!tyinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     /* Dump out in proper style */
@@ -11737,8 +11775,8 @@ dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
     DumpOptions *dopt = fout->dopt;
     PQExpBuffer q;

-    /* Skip if not to be dumped */
-    if (!stinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -11789,8 +11827,8 @@ dumpProcLang(Archive *fout, const ProcLangInfo *plang)
     FuncInfo   *inlineInfo = NULL;
     FuncInfo   *validatorInfo = NULL;

-    /* Skip if not to be dumped */
-    if (!plang->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     /*
@@ -12077,8 +12115,8 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
     const char *keyword;
     int            i;

-    /* Skip if not to be dumped */
-    if (!finfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     query = createPQExpBuffer();
@@ -12571,8 +12609,8 @@ dumpCast(Archive *fout, const CastInfo *cast)
     const char *sourceType;
     const char *targetType;

-    /* Skip if not to be dumped */
-    if (!cast->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     /* Cannot dump if we don't have the cast function's info */
@@ -12677,8 +12715,8 @@ dumpTransform(Archive *fout, const TransformInfo *transform)
     char       *lanname;
     const char *transformType;

-    /* Skip if not to be dumped */
-    if (!transform->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     /* Cannot dump if we don't have the transform functions' info */
@@ -12826,8 +12864,8 @@ dumpOpr(Archive *fout, const OprInfo *oprinfo)
     char       *oprregproc;
     char       *oprref;

-    /* Skip if not to be dumped */
-    if (!oprinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     /*
@@ -13119,8 +13157,8 @@ dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
     PQExpBuffer delq;
     char       *qamname;

-    /* Skip if not to be dumped */
-    if (!aminfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -13224,8 +13262,8 @@ dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
     bool        needComma;
     int            i;

-    /* Skip if not to be dumped */
-    if (!opcinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     query = createPQExpBuffer();
@@ -13586,8 +13624,8 @@ dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
     bool        needComma;
     int            i;

-    /* Skip if not to be dumped */
-    if (!opfinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     query = createPQExpBuffer();
@@ -13831,8 +13869,8 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
     const char *collcollate;
     const char *collctype;

-    /* Skip if not to be dumped */
-    if (!collinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     query = createPQExpBuffer();
@@ -13983,8 +14021,8 @@ dumpConversion(Archive *fout, const ConvInfo *convinfo)
     const char *conproc;
     bool        condefault;

-    /* Skip if not to be dumped */
-    if (!convinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     query = createPQExpBuffer();
@@ -14131,8 +14169,8 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
     const char *proparallel;
     char        defaultfinalmodify;

-    /* Skip if not to be dumped */
-    if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     query = createPQExpBuffer();
@@ -14465,8 +14503,8 @@ dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
     PQExpBuffer delq;
     char       *qprsname;

-    /* Skip if not to be dumped */
-    if (!prsinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -14533,8 +14571,8 @@ dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
     char       *nspname;
     char       *tmplname;

-    /* Skip if not to be dumped */
-    if (!dictinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -14609,8 +14647,8 @@ dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
     PQExpBuffer delq;
     char       *qtmplname;

-    /* Skip if not to be dumped */
-    if (!tmplinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -14675,8 +14713,8 @@ dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
     int            i_tokenname;
     int            i_dictname;

-    /* Skip if not to be dumped */
-    if (!cfginfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -14787,8 +14825,8 @@ dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
     PQExpBuffer delq;
     char       *qfdwname;

-    /* Skip if not to be dumped */
-    if (!fdwinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -14862,8 +14900,8 @@ dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
     char       *qsrvname;
     char       *fdwname;

-    /* Skip if not to be dumped */
-    if (!srvinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -15055,8 +15093,8 @@ dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
     PQExpBuffer tag;
     const char *type;

-    /* Skip if not to be dumped */
-    if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
+    /* Do nothing in data-only dump, or if we're skipping ACLs */
+    if (dopt->dataOnly || dopt->aclsSkip)
         return;

     q = createPQExpBuffer();
@@ -15411,20 +15449,12 @@ dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypenam
 static int
 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
 {
-    /* static storage for table of security labels */
-    static SecLabelItem *labels = NULL;
-    static int    nlabels = -1;
-
     SecLabelItem *middle = NULL;
     SecLabelItem *low;
     SecLabelItem *high;
     int            nmatch;

-    /* Get security labels if we didn't already */
-    if (nlabels < 0)
-        nlabels = collectSecLabels(fout, &labels);
-
-    if (nlabels <= 0)            /* no labels, so no match is possible */
+    if (nseclabels <= 0)        /* no labels, so no match is possible */
     {
         *items = NULL;
         return 0;
@@ -15433,8 +15463,8 @@ findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
     /*
      * Do binary search to find some item matching the object.
      */
-    low = &labels[0];
-    high = &labels[nlabels - 1];
+    low = &seclabels[0];
+    high = &seclabels[nseclabels - 1];
     while (low <= high)
     {
         middle = low + (high - low) / 2;
@@ -15490,13 +15520,13 @@ findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
 /*
  * collectSecLabels
  *
- * Construct a table of all security labels available for database objects.
- * It's much faster to pull them all at once.
+ * Construct a table of all security labels available for database objects;
+ * also set the has-seclabel component flag for each relevant object.
  *
  * The table is sorted by classoid/objid/objsubid for speed in lookup.
  */
-static int
-collectSecLabels(Archive *fout, SecLabelItem **items)
+static void
+collectSecLabels(Archive *fout)
 {
     PGresult   *res;
     PQExpBuffer query;
@@ -15507,7 +15537,7 @@ collectSecLabels(Archive *fout, SecLabelItem **items)
     int            i_objsubid;
     int            ntups;
     int            i;
-    SecLabelItem *labels;
+    DumpableObject *dobj;

     query = createPQExpBuffer();

@@ -15527,22 +15557,54 @@ collectSecLabels(Archive *fout, SecLabelItem **items)

     ntups = PQntuples(res);

-    labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
+    seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
+    nseclabels = 0;
+    dobj = NULL;

     for (i = 0; i < ntups; i++)
     {
-        labels[i].label = PQgetvalue(res, i, i_label);
-        labels[i].provider = PQgetvalue(res, i, i_provider);
-        labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
-        labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
-        labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
+        CatalogId    objId;
+        int            subid;
+
+        objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
+        objId.oid = atooid(PQgetvalue(res, i, i_objoid));
+        subid = atoi(PQgetvalue(res, i, i_objsubid));
+
+        /* We needn't remember labels that don't match any dumpable object */
+        if (dobj == NULL ||
+            dobj->catId.tableoid != objId.tableoid ||
+            dobj->catId.oid != objId.oid)
+            dobj = findObjectByCatalogId(objId);
+        if (dobj == NULL)
+            continue;
+
+        /*
+         * Labels on columns of composite types are linked to the type's
+         * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
+         * in the type's own DumpableObject.
+         */
+        if (subid != 0 && dobj->objType == DO_TABLE &&
+            ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
+        {
+            TypeInfo   *cTypeInfo;
+
+            cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
+            if (cTypeInfo)
+                cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
+        }
+        else
+            dobj->components |= DUMP_COMPONENT_SECLABEL;
+
+        seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
+        seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
+        seclabels[nseclabels].classoid = objId.tableoid;
+        seclabels[nseclabels].objoid = objId.oid;
+        seclabels[nseclabels].objsubid = subid;
+        nseclabels++;
     }

-    /* Do NOT free the PGresult since we are keeping pointers into it */
+    PQclear(res);
     destroyPQExpBuffer(query);
-
-    *items = labels;
-    return ntups;
 }

 /*
@@ -15556,17 +15618,17 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
     DumpId        tableAclDumpId = InvalidDumpId;
     char       *namecopy;

-    /*
-     * noop if we are not dumping anything about this table, or if we are
-     * doing a data-only dump
-     */
-    if (!tbinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

-    if (tbinfo->relkind == RELKIND_SEQUENCE)
-        dumpSequence(fout, tbinfo);
-    else
-        dumpTableSchema(fout, tbinfo);
+    if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+    {
+        if (tbinfo->relkind == RELKIND_SEQUENCE)
+            dumpSequence(fout, tbinfo);
+        else
+            dumpTableSchema(fout, tbinfo);
+    }

     /* Handle the ACL here */
     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
@@ -15586,7 +15648,8 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
     /*
      * 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.
+     * miss ACLs on system columns.  Doing it this way also allows us to dump
+     * ACLs for catalogs that we didn't mark "interesting" back in getTables.
      */
     if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
     {
@@ -15805,8 +15868,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
                        qrelname);

     if (dopt->binary_upgrade)
-        binary_upgrade_set_type_oids_by_rel_oid(fout, q,
-                                                tbinfo->dobj.catId.oid);
+        binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);

     /* Is it a table or a view? */
     if (tbinfo->relkind == RELKIND_VIEW)
@@ -16556,6 +16618,7 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
     DumpOptions *dopt = fout->dopt;
     PQExpBuffer q;

+    /* Do nothing in data-only dump */
     if (dopt->dataOnly)
         return;

@@ -16606,8 +16669,8 @@ dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
     char       *tag;
     char       *foreign;

-    /* Skip if table definition not to be dumped */
-    if (!tbinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     /* Skip if not "separate"; it was dumped in the table's definition */
@@ -16695,6 +16758,7 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo)
     char       *qindxname;
     char       *qqindxname;

+    /* Do nothing in data-only dump */
     if (dopt->dataOnly)
         return;

@@ -16829,6 +16893,7 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo)
 static void
 dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
 {
+    /* Do nothing in data-only dump */
     if (fout->dopt->dataOnly)
         return;

@@ -16875,8 +16940,8 @@ dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
     PGresult   *res;
     char       *stxdef;

-    /* Skip if not to be dumped */
-    if (!statsextinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -16952,8 +17017,8 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
     char       *tag = NULL;
     char       *foreign;

-    /* Skip if not to be dumped */
-    if (!coninfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     q = createPQExpBuffer();
@@ -17605,10 +17670,7 @@ dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
     int            findx;
     char       *tag;

-    /*
-     * we needn't check dobj.dump because TriggerInfo wouldn't have been
-     * created in the first place for non-dumpable triggers
-     */
+    /* Do nothing in data-only dump */
     if (dopt->dataOnly)
         return;

@@ -17844,8 +17906,8 @@ dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
     PQExpBuffer delqry;
     char       *qevtname;

-    /* Skip if not to be dumped */
-    if (!evtinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     query = createPQExpBuffer();
@@ -17935,8 +17997,8 @@ dumpRule(Archive *fout, const RuleInfo *rinfo)
     PGresult   *res;
     char       *tag;

-    /* Skip if not to be dumped */
-    if (!rinfo->dobj.dump || dopt->dataOnly)
+    /* Do nothing in data-only dump */
+    if (dopt->dataOnly)
         return;

     /*
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index d1d8608e9c..6e9a76103c 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -85,8 +85,13 @@ typedef enum
     DO_SUBSCRIPTION
 } DumpableObjectType;

-/* component types of an object which can be selected for dumping */
-typedef uint32 DumpComponents;    /* a bitmask of dump object components */
+/*
+ * DumpComponents is a bitmask of the potentially dumpable components of
+ * a database object: its core definition, plus optional attributes such
+ * as ACL, comments, etc.  The NONE and ALL symbols are convenient
+ * shorthands.
+ */
+typedef uint32 DumpComponents;
 #define DUMP_COMPONENT_NONE            (0)
 #define DUMP_COMPONENT_DEFINITION    (1 << 0)
 #define DUMP_COMPONENT_DATA            (1 << 1)
@@ -131,8 +136,9 @@ 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 requested to dump */
     DumpComponents dump_contains;    /* as above, but for contained objects */
+    DumpComponents components;    /* bitmask of components available to dump */
     bool        ext_member;        /* true if object is member of extension */
     bool        depends_on_ext; /* true if object depends on an extension */
     DumpId       *dependencies;    /* dumpIds of objects this one depends on */
@@ -289,6 +295,7 @@ typedef struct _tableInfo
     uint32        toast_frozenxid;    /* toast table's relfrozenxid, if any */
     uint32        toast_minmxid;    /* toast table's relminmxid */
     int            ncheck;            /* # of CHECK expressions */
+    Oid            reltype;        /* OID of table's composite type, if any */
     char       *reloftype;        /* underlying type for typed table */
     Oid            foreign_server; /* foreign server oid, if applicable */
     /* these two are set only if table is a sequence owned by a column: */
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index ea67e52a3f..6e216313c6 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -24,7 +24,7 @@ static bool parseAclItem(const char *item, const char *type,
                          const char *name, const char *subname, int remoteVersion,
                          PQExpBuffer grantee, PQExpBuffer grantor,
                          PQExpBuffer privs, PQExpBuffer privswgo);
-static char *copyAclUserName(PQExpBuffer output, char *input);
+static char *dequoteAclUserName(PQExpBuffer output, char *input);
 static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
                    const char *subname);

@@ -39,7 +39,8 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  *        TABLE, SEQUENCE, FUNCTION, PROCEDURE, 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
+ *    baseacls: the initial ACL string for this object; can be
+ *        NULL or empty string to indicate "not available from server"
  *    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
@@ -48,6 +49,12 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  * Returns true if okay, false if could not parse the acl string.
  * The resulting commands (if any) are appended to the contents of 'sql'.
  *
+ * baseacls is typically the result of acldefault() for the object's type
+ * and owner.  However, if there is a pg_init_privs entry for the object,
+ * it should instead be the initprivs ACLs.  When acls is itself a
+ * pg_init_privs entry, baseacls is what to dump that relative to; then
+ * it can be either an acldefault() value or an empty ACL "{}".
+ *
  * Note: when processing a default ACL, prefix is "ALTER DEFAULT PRIVILEGES "
  * or something similar, and name is an empty string.
  *
@@ -56,15 +63,19 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  */
 bool
 buildACLCommands(const char *name, const char *subname, const char *nspname,
-                 const char *type, const char *acls, const char *racls,
+                 const char *type, const char *acls, const char *baseacls,
                  const char *owner, const char *prefix, int remoteVersion,
                  PQExpBuffer sql)
 {
     bool        ok = true;
     char      **aclitems = NULL;
-    char      **raclitems = NULL;
+    char      **baseitems = NULL;
+    char      **grantitems = NULL;
+    char      **revokeitems = NULL;
     int            naclitems = 0;
-    int            nraclitems = 0;
+    int            nbaseitems = 0;
+    int            ngrantitems = 0;
+    int            nrevokeitems = 0;
     int            i;
     PQExpBuffer grantee,
                 grantor,
@@ -72,37 +83,88 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
                 privswgo;
     PQExpBuffer firstsql,
                 secondsql;
-    bool        found_owner_privs = false;

-    if (strlen(acls) == 0 && strlen(racls) == 0)
+    /*
+     * If the acl was NULL (initial default state), we need do nothing.  Note
+     * that this is distinguishable from all-privileges-revoked, which will
+     * look like an empty array ("{}").
+     */
+    if (acls == NULL || *acls == '\0')
         return true;            /* object has default permissions */

     /* treat empty-string owner same as NULL */
     if (owner && *owner == '\0')
         owner = NULL;

-    if (strlen(acls) != 0)
+    /* Parse the acls array */
+    if (!parsePGArray(acls, &aclitems, &naclitems))
+    {
+        if (aclitems)
+            free(aclitems);
+        return false;
+    }
+
+    /* Parse the baseacls, if provided */
+    if (baseacls && *baseacls != '\0')
     {
-        if (!parsePGArray(acls, &aclitems, &naclitems))
+        if (!parsePGArray(baseacls, &baseitems, &nbaseitems))
         {
             if (aclitems)
                 free(aclitems);
+            if (baseitems)
+                free(baseitems);
             return false;
         }
     }

-    if (strlen(racls) != 0)
+    /*
+     * Compare the actual ACL with the base ACL, extracting the privileges
+     * that need to be granted (i.e., are in the actual ACL but not the base
+     * ACL) and the ones that need to be revoked (the reverse).  We use plain
+     * string comparisons to check for matches.  In principle that could be
+     * fooled by extraneous issues such as whitespace, but since all these
+     * strings are the work of aclitemout(), it should be OK in practice.
+     * Besides, a false mismatch will just cause the output to be a little
+     * more verbose than it really needed to be.
+     *
+     * (If we weren't given a base ACL, this stanza winds up with all the
+     * ACL's items in grantitems and nothing in revokeitems.  It's not worth
+     * special-casing that.)
+     */
+    grantitems = (char **) pg_malloc(naclitems * sizeof(char *));
+    for (i = 0; i < naclitems; i++)
     {
-        if (!parsePGArray(racls, &raclitems, &nraclitems))
+        bool        found = false;
+
+        for (int j = 0; j < nbaseitems; j++)
         {
-            if (aclitems)
-                free(aclitems);
-            if (raclitems)
-                free(raclitems);
-            return false;
+            if (strcmp(aclitems[i], baseitems[j]) == 0)
+            {
+                found = true;
+                break;
+            }
         }
+        if (!found)
+            grantitems[ngrantitems++] = aclitems[i];
     }
+    revokeitems = (char **) pg_malloc(nbaseitems * sizeof(char *));
+    for (i = 0; i < nbaseitems; i++)
+    {
+        bool        found = false;

+        for (int j = 0; j < naclitems; j++)
+        {
+            if (strcmp(baseitems[i], aclitems[j]) == 0)
+            {
+                found = true;
+                break;
+            }
+        }
+        if (!found)
+            revokeitems[nrevokeitems++] = baseitems[i];
+    }
+
+    /* Prepare working buffers */
     grantee = createPQExpBuffer();
     grantor = createPQExpBuffer();
     privs = createPQExpBuffer();
@@ -110,50 +172,21 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,

     /*
      * 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();

     /*
-     * 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'.
+     * If we weren't given baseacls information, we just revoke everything and
+     * then grant what's listed in the ACL.  This avoids having to embed
+     * detailed knowledge about what the defaults are/were, and it's not very
+     * expensive since servers lacking acldefault() are now rare.
      *
-     * 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.
+     * Otherwise, we need only revoke what's listed in revokeitems.
      */
-    if (remoteVersion < 90600)
+    if (baseacls == NULL || *baseacls == '\0')
     {
-        Assert(nraclitems == 0);
-
+        /* We assume the old defaults only involved the owner and PUBLIC */
         appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
         if (subname)
             appendPQExpBuffer(firstsql, "(%s)", subname);
@@ -161,13 +194,24 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
         if (nspname && *nspname)
             appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
         appendPQExpBuffer(firstsql, "%s FROM PUBLIC;\n", name);
+        if (owner)
+        {
+            appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
+            if (subname)
+                appendPQExpBuffer(firstsql, "(%s)", subname);
+            appendPQExpBuffer(firstsql, " ON %s ", type);
+            if (nspname && *nspname)
+                appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
+            appendPQExpBuffer(firstsql, "%s FROM %s;\n", name, fmtId(owner));
+        }
     }
     else
     {
         /* Scan individual REVOKE ACL items */
-        for (i = 0; i < nraclitems; i++)
+        for (i = 0; i < nrevokeitems; i++)
         {
-            if (!parseAclItem(raclitems[i], type, name, subname, remoteVersion,
+            if (!parseAclItem(revokeitems[i],
+                              type, name, subname, remoteVersion,
                               grantee, grantor, privs, NULL))
             {
                 ok = false;
@@ -195,6 +239,10 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
     }

     /*
+     * At this point we have issued REVOKE statements for all initial and
+     * default privileges that are no longer present on the object, so we are
+     * almost ready to GRANT the privileges listed in grantitems[].
+     *
      * We still need some hacking though to cover the case where new default
      * public privileges are added in new versions: the REVOKE ALL will revoke
      * them, leading to behavior different from what the old version had,
@@ -208,146 +256,92 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
                           prefix, type, name);
     }

-    /* Scan individual ACL items */
-    for (i = 0; i < naclitems; i++)
+    /*
+     * Scan individual ACL items to be granted.
+     *
+     * The order in which privileges appear in the ACL string (the order they
+     * have been GRANT'd in, which the backend maintains) must be preserved to
+     * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
+     * those are dumped in the correct order.  However, some old server
+     * versions will show grants to PUBLIC before the owner's own grants; for
+     * consistency's sake, force the owner's grants to be output first.
+     */
+    for (i = 0; i < ngrantitems; i++)
     {
-        if (!parseAclItem(aclitems[i], type, name, subname, remoteVersion,
-                          grantee, grantor, privs, privswgo))
-        {
-            ok = false;
-            break;
-        }
-
-        if (grantor->len == 0 && owner)
-            printfPQExpBuffer(grantor, "%s", owner);
-
-        if (privs->len > 0 || privswgo->len > 0)
+        if (parseAclItem(grantitems[i], type, name, subname, remoteVersion,
+                         grantee, grantor, privs, privswgo))
         {
             /*
-             * 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", respectively.  See above.
+             * If the grantor isn't the owner, we'll need to use SET SESSION
+             * AUTHORIZATION to become the grantor.  Issue the SET/RESET only
+             * if there's something useful to do.
              */
-            if (remoteVersion < 90600 && owner
-                && strcmp(grantee->data, owner) == 0
-                && strcmp(grantor->data, owner) == 0)
+            if (privs->len > 0 || privswgo->len > 0)
             {
-                found_owner_privs = true;
+                PQExpBuffer thissql;
+
+                /* Set owner as grantor if that's not explicit in the ACL */
+                if (grantor->len == 0 && owner)
+                    printfPQExpBuffer(grantor, "%s", owner);
+
+                /* Make sure owner's own grants are output before others */
+                if (owner &&
+                    strcmp(grantee->data, owner) == 0 &&
+                    strcmp(grantor->data, owner) == 0)
+                    thissql = firstsql;
+                else
+                    thissql = secondsql;

-                /*
-                 * For the owner, the default privilege level is ALL WITH
-                 * GRANT OPTION.
-                 */
-                if (strcmp(privswgo->data, "ALL") != 0)
-                {
-                    appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
-                    if (subname)
-                        appendPQExpBuffer(firstsql, "(%s)", subname);
-                    appendPQExpBuffer(firstsql, " ON %s ", type);
-                    if (nspname && *nspname)
-                        appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
-                    appendPQExpBuffer(firstsql, "%s FROM %s;\n",
-                                      name, fmtId(grantee->data));
-                    if (privs->len > 0)
-                    {
-                        appendPQExpBuffer(firstsql,
-                                          "%sGRANT %s ON %s ",
-                                          prefix, privs->data, type);
-                        if (nspname && *nspname)
-                            appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
-                        appendPQExpBuffer(firstsql,
-                                          "%s TO %s;\n",
-                                          name, fmtId(grantee->data));
-                    }
-                    if (privswgo->len > 0)
-                    {
-                        appendPQExpBuffer(firstsql,
-                                          "%sGRANT %s ON %s ",
-                                          prefix, privswgo->data, type);
-                        if (nspname && *nspname)
-                            appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
-                        appendPQExpBuffer(firstsql,
-                                          "%s TO %s WITH GRANT OPTION;\n",
-                                          name, fmtId(grantee->data));
-                    }
-                }
-            }
-            else
-            {
-                /*
-                 * 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))
-                    appendPQExpBuffer(secondsql, "SET SESSION AUTHORIZATION %s;\n",
+                    appendPQExpBuffer(thissql, "SET SESSION AUTHORIZATION %s;\n",
                                       fmtId(grantor->data));

                 if (privs->len > 0)
                 {
-                    appendPQExpBuffer(secondsql, "%sGRANT %s ON %s ",
+                    appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
                                       prefix, privs->data, type);
                     if (nspname && *nspname)
-                        appendPQExpBuffer(secondsql, "%s.", fmtId(nspname));
-                    appendPQExpBuffer(secondsql, "%s TO ", name);
+                        appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
+                    appendPQExpBuffer(thissql, "%s TO ", name);
                     if (grantee->len == 0)
-                        appendPQExpBufferStr(secondsql, "PUBLIC;\n");
+                        appendPQExpBufferStr(thissql, "PUBLIC;\n");
                     else if (strncmp(grantee->data, "group ",
                                      strlen("group ")) == 0)
-                        appendPQExpBuffer(secondsql, "GROUP %s;\n",
+                        appendPQExpBuffer(thissql, "GROUP %s;\n",
                                           fmtId(grantee->data + strlen("group ")));
                     else
-                        appendPQExpBuffer(secondsql, "%s;\n", fmtId(grantee->data));
+                        appendPQExpBuffer(thissql, "%s;\n", fmtId(grantee->data));
                 }
                 if (privswgo->len > 0)
                 {
-                    appendPQExpBuffer(secondsql, "%sGRANT %s ON %s ",
+                    appendPQExpBuffer(thissql, "%sGRANT %s ON %s ",
                                       prefix, privswgo->data, type);
                     if (nspname && *nspname)
-                        appendPQExpBuffer(secondsql, "%s.", fmtId(nspname));
-                    appendPQExpBuffer(secondsql, "%s TO ", name);
+                        appendPQExpBuffer(thissql, "%s.", fmtId(nspname));
+                    appendPQExpBuffer(thissql, "%s TO ", name);
                     if (grantee->len == 0)
-                        appendPQExpBufferStr(secondsql, "PUBLIC");
+                        appendPQExpBufferStr(thissql, "PUBLIC");
                     else if (strncmp(grantee->data, "group ",
                                      strlen("group ")) == 0)
-                        appendPQExpBuffer(secondsql, "GROUP %s",
+                        appendPQExpBuffer(thissql, "GROUP %s",
                                           fmtId(grantee->data + strlen("group ")));
                     else
-                        appendPQExpBufferStr(secondsql, fmtId(grantee->data));
-                    appendPQExpBufferStr(secondsql, " WITH GRANT OPTION;\n");
+                        appendPQExpBufferStr(thissql, fmtId(grantee->data));
+                    appendPQExpBufferStr(thissql, " WITH GRANT OPTION;\n");
                 }

                 if (grantor->len > 0
                     && (!owner || strcmp(owner, grantor->data) != 0))
-                    appendPQExpBufferStr(secondsql, "RESET SESSION AUTHORIZATION;\n");
+                    appendPQExpBufferStr(thissql, "RESET SESSION AUTHORIZATION;\n");
             }
         }
-    }
-
-    /*
-     * 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 (remoteVersion < 90600 && !found_owner_privs && owner)
-    {
-        appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
-        if (subname)
-            appendPQExpBuffer(firstsql, "(%s)", subname);
-        appendPQExpBuffer(firstsql, " ON %s ", type);
-        if (nspname && *nspname)
-            appendPQExpBuffer(firstsql, "%s.", fmtId(nspname));
-        appendPQExpBuffer(firstsql, "%s FROM %s;\n",
-                          name, fmtId(owner));
+        else
+        {
+            /* parseAclItem failed, give up */
+            ok = false;
+            break;
+        }
     }

     destroyPQExpBuffer(grantee);
@@ -361,19 +355,23 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,

     if (aclitems)
         free(aclitems);
-
-    if (raclitems)
-        free(raclitems);
+    if (baseitems)
+        free(baseitems);
+    if (grantitems)
+        free(grantitems);
+    if (revokeitems)
+        free(revokeitems);

     return ok;
 }

 /*
- * Build ALTER DEFAULT PRIVILEGES command(s) for single pg_default_acl entry.
+ * Build ALTER DEFAULT PRIVILEGES command(s) for a single pg_default_acl entry.
  *
  *    type: the object type (TABLES, FUNCTIONS, etc)
  *    nspname: schema name, or NULL for global default privileges
  *    acls: the ACL string fetched from the database
+ *    acldefault: the appropriate default ACL for the object type and owner
  *    owner: username of privileges owner (will be passed through fmtId)
  *    remoteVersion: version of database
  *
@@ -382,8 +380,7 @@ buildACLCommands(const char *name, const char *subname, const char *nspname,
  */
 bool
 buildDefaultACLCommands(const char *type, const char *nspname,
-                        const char *acls, const char *racls,
-                        const char *initacls, const char *initracls,
+                        const char *acls, const char *acldefault,
                         const char *owner,
                         int remoteVersion,
                         PQExpBuffer sql)
@@ -403,21 +400,12 @@ buildDefaultACLCommands(const char *type, const char *nspname,
     if (nspname)
         appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));

-    if (strlen(initacls) != 0 || strlen(initracls) != 0)
-    {
-        appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
-        if (!buildACLCommands("", NULL, NULL, type,
-                              initacls, initracls, owner,
-                              prefix->data, remoteVersion, sql))
-        {
-            destroyPQExpBuffer(prefix);
-            return false;
-        }
-        appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
-    }
-
+    /*
+     * There's no such thing as initprivs for a default ACL, so the base ACL
+     * is always just the object-type-specific default.
+     */
     if (!buildACLCommands("", NULL, NULL, type,
-                          acls, racls, owner,
+                          acls, acldefault, owner,
                           prefix->data, remoteVersion, sql))
     {
         destroyPQExpBuffer(prefix);
@@ -467,7 +455,7 @@ parseAclItem(const char *item, const char *type,
     buf = pg_strdup(item);

     /* user or group name is string up to = */
-    eqpos = copyAclUserName(grantee, buf);
+    eqpos = dequoteAclUserName(grantee, buf);
     if (*eqpos != '=')
     {
         pg_free(buf);
@@ -479,7 +467,7 @@ parseAclItem(const char *item, const char *type,
     if (slpos)
     {
         *slpos++ = '\0';
-        slpos = copyAclUserName(grantor, slpos);
+        slpos = dequoteAclUserName(grantor, slpos);
         if (*slpos != '\0')
         {
             pg_free(buf);
@@ -603,13 +591,46 @@ do { \
     return true;
 }

+/*
+ * Transfer the role name at *input into the output buffer, adding
+ * quoting according to the same rules as putid() in backend's acl.c.
+ */
+void
+quoteAclUserName(PQExpBuffer output, const char *input)
+{
+    const char *src;
+    bool        safe = true;
+
+    for (src = input; *src; src++)
+    {
+        /* This test had better match what putid() does */
+        if (!isalnum((unsigned char) *src) && *src != '_')
+        {
+            safe = false;
+            break;
+        }
+    }
+    if (!safe)
+        appendPQExpBufferChar(output, '"');
+    for (src = input; *src; src++)
+    {
+        /* A double quote character in a username is encoded as "" */
+        if (*src == '"')
+            appendPQExpBufferChar(output, '"');
+        appendPQExpBufferChar(output, *src);
+    }
+    if (!safe)
+        appendPQExpBufferChar(output, '"');
+}
+
 /*
  * Transfer a user or group name starting at *input into the output buffer,
  * dequoting if needed.  Returns a pointer to just past the input name.
  * The name is taken to end at an unquoted '=' or end of string.
+ * Note: unlike quoteAclUserName(), this first clears the output buffer.
  */
 static char *
-copyAclUserName(PQExpBuffer output, char *input)
+dequoteAclUserName(PQExpBuffer output, char *input)
 {
     resetPQExpBuffer(output);

@@ -708,137 +729,6 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
     }
 }

-/*
- * 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 *initprivs_expr,
-                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).
-     *
-     * Finally, the order in which privileges are in the ACL string (the order
-     * they been GRANT'd in, which the backend maintains) must be preserved to
-     * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
-     * those are dumped in the correct order.
-     */
-    printfPQExpBuffer(acl_subquery,
-                      "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "
-                      "(SELECT acl, row_n FROM "
-                      "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "
-                      "WITH ORDINALITY AS perm(acl,row_n) "
-                      "WHERE NOT EXISTS ( "
-                      "SELECT 1 FROM "
-                      "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "
-                      "AS init(init_acl) WHERE acl = init_acl)) as foo)",
-                      acl_column,
-                      obj_kind,
-                      acl_owner,
-                      initprivs_expr,
-                      obj_kind,
-                      acl_owner);
-
-    printfPQExpBuffer(racl_subquery,
-                      "(SELECT pg_catalog.array_agg(acl ORDER BY row_n) FROM "
-                      "(SELECT acl, row_n FROM "
-                      "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "
-                      "WITH ORDINALITY AS initp(acl,row_n) "
-                      "WHERE NOT EXISTS ( "
-                      "SELECT 1 FROM "
-                      "pg_catalog.unnest(coalesce(%s,pg_catalog.acldefault(%s,%s))) "
-                      "AS permp(orig_acl) WHERE acl = orig_acl)) as foo)",
-                      initprivs_expr,
-                      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 pg_catalog.array_agg(acl ORDER BY row_n) FROM "
-                          "(SELECT acl, row_n FROM pg_catalog.unnest(%s) "
-                          "WITH ORDINALITY AS initp(acl,row_n) "
-                          "WHERE NOT EXISTS ( "
-                          "SELECT 1 FROM "
-                          "pg_catalog.unnest(pg_catalog.acldefault(%s,%s)) "
-                          "AS privm(orig_acl) WHERE acl = orig_acl)) as foo) END",
-                          initprivs_expr,
-                          obj_kind,
-                          acl_owner);
-
-        printfPQExpBuffer(init_racl_subquery,
-                          "CASE WHEN privtype = 'e' THEN "
-                          "(SELECT pg_catalog.array_agg(acl) FROM "
-                          "(SELECT acl, row_n FROM "
-                          "pg_catalog.unnest(pg_catalog.acldefault(%s,%s)) "
-                          "WITH ORDINALITY AS privp(acl,row_n) "
-                          "WHERE NOT EXISTS ( "
-                          "SELECT 1 FROM pg_catalog.unnest(%s) "
-                          "AS initp(init_acl) WHERE acl = init_acl)) as foo) END",
-                          obj_kind,
-                          acl_owner,
-                          initprivs_expr);
-    }
-    else
-    {
-        printfPQExpBuffer(init_acl_subquery, "NULL");
-        printfPQExpBuffer(init_racl_subquery, "NULL");
-    }
-}

 /*
  * Detect whether the given GUC variable is of GUC_LIST_QUOTE type.
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index f5465f19ae..fac7a05c91 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -37,26 +37,22 @@


 extern bool buildACLCommands(const char *name, const char *subname, const char *nspname,
-                             const char *type, const char *acls, const char *racls,
+                             const char *type, const char *acls, const char *baseacls,
                              const char *owner, const char *prefix, int remoteVersion,
                              PQExpBuffer sql);
 extern bool buildDefaultACLCommands(const char *type, const char *nspname,
-                                    const char *acls, const char *racls,
-                                    const char *initacls, const char *initracls,
+                                    const char *acls, const char *acldefault,
                                     const char *owner,
                                     int remoteVersion,
                                     PQExpBuffer sql);
+
+extern void quoteAclUserName(PQExpBuffer output, const char *input);
+
 extern void buildShSecLabelQuery(const char *catalog_name,
                                  Oid objectId, PQExpBuffer sql);
 extern void emitShSecLabels(PGconn *conn, PGresult *res,
                             PQExpBuffer buffer, const char *objtype, 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 *initprivs_expr,
-                            const char *obj_kind, bool binary_upgrade);
-
 extern bool variable_is_guc_list_quote(const char *name);

 extern bool SplitGUCList(char *rawstring, char separator,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 15f55cbb19..75ea57266e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -179,6 +179,7 @@ static NamespaceInfo *findNamespace(Oid nsoid);
 static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
 static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
+static void getAdditionalACLs(Archive *fout);
 static void dumpCommentExtended(Archive *fout, const char *type,
                                 const char *name, const char *namespace,
                                 const char *owner, CatalogId catalogId,
@@ -248,8 +249,7 @@ static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
 static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
                       const char *type, const char *name, const char *subname,
                       const char *nspname, const char *owner,
-                      const char *acls, const char *racls,
-                      const char *initacls, const char *initracls);
+                      const DumpableAcl *dacl);

 static void getDependencies(Archive *fout);
 static void BuildArchiveDependencies(Archive *fout);
@@ -888,8 +888,10 @@ main(int argc, char **argv)
     getDependencies(fout);

     /*
-     * Collect comments and security labels, if wanted.
+     * Collect ACLs, comments, and security labels, if wanted.
      */
+    if (!dopt.aclsSkip)
+        getAdditionalACLs(fout);
     if (!dopt.no_comments)
         collectComments(fout);
     if (!dopt.no_security_labels)
@@ -2859,19 +2861,18 @@ dumpDatabase(Archive *fout)
                 i_frozenxid,
                 i_minmxid,
                 i_datacl,
-                i_rdatacl,
+                i_acldefault,
                 i_datistemplate,
                 i_datconnlimit,
                 i_tablespace;
     CatalogId    dbCatId;
     DumpId        dbDumpId;
+    DumpableAcl dbdacl;
     const char *datname,
                *dba,
                *encoding,
                *collate,
                *ctype,
-               *datacl,
-               *rdatacl,
                *datistemplate,
                *datconnlimit,
                *tablespace;
@@ -2883,40 +2884,14 @@ dumpDatabase(Archive *fout)

     /*
      * Fetch the database-level properties for this database.
-     *
-     * The order in which privileges are in the ACL string (the order they
-     * have been GRANT'd in, which the backend maintains) must be preserved to
-     * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
-     * those are dumped in the correct order.  Note that initial privileges
-     * (pg_init_privs) are not supported on databases, so this logic cannot
-     * make use of buildACLQueries().
      */
-    if (fout->remoteVersion >= 90600)
+    if (fout->remoteVersion >= 90300)
     {
         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
                           "(%s datdba) AS dba, "
                           "pg_encoding_to_char(encoding) AS encoding, "
                           "datcollate, datctype, datfrozenxid, datminmxid, "
-                          "(SELECT array_agg(acl ORDER BY row_n) FROM "
-                          "  (SELECT acl, row_n FROM "
-                          "     unnest(coalesce(datacl,acldefault('d',datdba))) "
-                          "     WITH ORDINALITY AS perm(acl,row_n) "
-                          "   WHERE NOT EXISTS ( "
-                          "     SELECT 1 "
-                          "     FROM unnest(acldefault('d',datdba)) "
-                          "       AS init(init_acl) "
-                          "     WHERE acl = init_acl)) AS datacls) "
-                          " AS datacl, "
-                          "(SELECT array_agg(acl ORDER BY row_n) FROM "
-                          "  (SELECT acl, row_n FROM "
-                          "     unnest(acldefault('d',datdba)) "
-                          "     WITH ORDINALITY AS initp(acl,row_n) "
-                          "   WHERE NOT EXISTS ( "
-                          "     SELECT 1 "
-                          "     FROM unnest(coalesce(datacl,acldefault('d',datdba))) "
-                          "       AS permp(orig_acl) "
-                          "     WHERE acl = orig_acl)) AS rdatacls) "
-                          " AS rdatacl, "
+                          "datacl, acldefault('d', datdba) AS acldefault, "
                           "datistemplate, datconnlimit, "
                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
                           "shobj_description(oid, 'pg_database') AS description "
@@ -2925,13 +2900,14 @@ dumpDatabase(Archive *fout)
                           "WHERE datname = current_database()",
                           username_subquery);
     }
-    else if (fout->remoteVersion >= 90300)
+    else if (fout->remoteVersion >= 90200)
     {
         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
                           "(%s datdba) AS dba, "
                           "pg_encoding_to_char(encoding) AS encoding, "
-                          "datcollate, datctype, datfrozenxid, datminmxid, "
-                          "datacl, '' as rdatacl, datistemplate, datconnlimit, "
+                          "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
+                          "datacl, acldefault('d', datdba) AS acldefault, "
+                          "datistemplate, datconnlimit, "
                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
                           "shobj_description(oid, 'pg_database') AS description "

@@ -2945,7 +2921,8 @@ dumpDatabase(Archive *fout)
                           "(%s datdba) AS dba, "
                           "pg_encoding_to_char(encoding) AS encoding, "
                           "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
-                          "datacl, '' as rdatacl, datistemplate, datconnlimit, "
+                          "datacl, NULL AS acldefault, "
+                          "datistemplate, datconnlimit, "
                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
                           "shobj_description(oid, 'pg_database') AS description "

@@ -2959,7 +2936,8 @@ dumpDatabase(Archive *fout)
                           "(%s datdba) AS dba, "
                           "pg_encoding_to_char(encoding) AS encoding, "
                           "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
-                          "datacl, '' as rdatacl, datistemplate, datconnlimit, "
+                          "datacl, NULL AS acldefault, "
+                          "datistemplate, datconnlimit, "
                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
                           "shobj_description(oid, 'pg_database') AS description "

@@ -2973,8 +2951,8 @@ dumpDatabase(Archive *fout)
                           "(%s datdba) AS dba, "
                           "pg_encoding_to_char(encoding) AS encoding, "
                           "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
-                          "datacl, '' as rdatacl, datistemplate, "
-                          "-1 as datconnlimit, "
+                          "datacl, NULL AS acldefault, "
+                          "datistemplate, -1 AS datconnlimit, "
                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
                           "FROM pg_database "
                           "WHERE datname = current_database()",
@@ -2993,7 +2971,7 @@ dumpDatabase(Archive *fout)
     i_frozenxid = PQfnumber(res, "datfrozenxid");
     i_minmxid = PQfnumber(res, "datminmxid");
     i_datacl = PQfnumber(res, "datacl");
-    i_rdatacl = PQfnumber(res, "rdatacl");
+    i_acldefault = PQfnumber(res, "acldefault");
     i_datistemplate = PQfnumber(res, "datistemplate");
     i_datconnlimit = PQfnumber(res, "datconnlimit");
     i_tablespace = PQfnumber(res, "tablespace");
@@ -3007,8 +2985,8 @@ dumpDatabase(Archive *fout)
     ctype = PQgetvalue(res, 0, i_ctype);
     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
-    datacl = PQgetvalue(res, 0, i_datacl);
-    rdatacl = PQgetvalue(res, 0, i_rdatacl);
+    dbdacl.acl = PQgetvalue(res, 0, i_datacl);
+    dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
     datistemplate = PQgetvalue(res, 0, i_datistemplate);
     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
     tablespace = PQgetvalue(res, 0, i_tablespace);
@@ -3146,9 +3124,12 @@ dumpDatabase(Archive *fout)
      * Dump ACL if any.  Note that we do not support initial privileges
      * (pg_init_privs) on databases.
      */
+    dbdacl.privtype = 0;
+    dbdacl.initprivs = NULL;
+
     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
             qdatname, NULL, NULL,
-            dba, datacl, rdatacl, "", "");
+            dba, &dbdacl);

     /*
      * Now construct a DATABASE PROPERTIES archive entry to restore any
@@ -3470,59 +3451,30 @@ getBlobs(Archive *fout)
     int            i_oid;
     int            i_lomowner;
     int            i_lomacl;
-    int            i_rlomacl;
-    int            i_initlomacl;
-    int            i_initrlomacl;
+    int            i_acldefault;

     pg_log_info("reading large objects");

     /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
-    if (fout->remoteVersion >= 90600)
+    if (fout->remoteVersion >= 90200)
     {
-        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",
-                        "pip.initprivs", "'L'", dopt->binary_upgrade);
-
         appendPQExpBuffer(blobQry,
-                          "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 = 'pg_largeobject'::regclass "
-                          "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);
+                          "SELECT oid, (%s lomowner) AS rolname, lomacl, "
+                          "acldefault('L', lomowner) AS acldefault "
+                          "FROM pg_largeobject_metadata",
+                          username_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",
+                          "NULL AS acldefault "
+                          "FROM pg_largeobject_metadata",
                           username_subquery);
     else
         appendPQExpBufferStr(blobQry,
                              "SELECT DISTINCT loid AS oid, "
                              "NULL::name AS rolname, NULL::oid AS lomacl, "
-                             "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
-                             "NULL::oid AS initrlomacl "
+                             "NULL::oid AS acldefault "
                              " FROM pg_largeobject");

     res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
@@ -3530,9 +3482,7 @@ getBlobs(Archive *fout)
     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");
+    i_acldefault = PQfnumber(res, "acldefault");

     ntups = PQntuples(res);

@@ -3549,20 +3499,17 @@ getBlobs(Archive *fout)
         AssignDumpId(&binfo[i].dobj);

         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
+        binfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lomacl));
+        binfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        binfo[i].dacl.privtype = 0;
+        binfo[i].dacl.initprivs = NULL;
         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));

         /* Blobs have data */
         binfo[i].dobj.components |= DUMP_COMPONENT_DATA;

         /* Mark whether blob has an ACL */
-        if (!(PQgetisnull(res, i, i_lomacl) &&
-              PQgetisnull(res, i, i_rlomacl) &&
-              PQgetisnull(res, i, i_initlomacl) &&
-              PQgetisnull(res, i, i_initrlomacl)))
+        if (!PQgetisnull(res, i, i_lomacl))
             binfo[i].dobj.components |= DUMP_COMPONENT_ACL;

         /*
@@ -3638,8 +3585,7 @@ dumpBlob(Archive *fout, const BlobInfo *binfo)
     if (binfo->dobj.dump & DUMP_COMPONENT_ACL)
         dumpACL(fout, binfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
                 binfo->dobj.name, NULL,
-                NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
-                binfo->initblobacl, binfo->initrblobacl);
+                NULL, binfo->rolname, &binfo->dacl);

     destroyPQExpBuffer(cquery);
     destroyPQExpBuffer(dquery);
@@ -4999,7 +4945,6 @@ binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
 NamespaceInfo *
 getNamespaces(Archive *fout, int *numNamespaces)
 {
-    DumpOptions *dopt = fout->dopt;
     PGresult   *res;
     int            ntups;
     int            i;
@@ -5011,9 +4956,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
     int            i_nspowner;
     int            i_rolname;
     int            i_nspacl;
-    int            i_rnspacl;
-    int            i_initnspacl;
-    int            i_initrnspacl;
+    int            i_acldefault;

     query = createPQExpBuffer();

@@ -5021,67 +4964,18 @@ 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.
      */
-    if (fout->remoteVersion >= 90600)
-    {
-        PQExpBuffer acl_subquery = createPQExpBuffer();
-        PQExpBuffer racl_subquery = createPQExpBuffer();
-        PQExpBuffer init_acl_subquery = createPQExpBuffer();
-        PQExpBuffer init_racl_subquery = createPQExpBuffer();
-
-        /*
-         * Bypass pg_init_privs.initprivs for the public schema, for several
-         * reasons.  First, dropping and recreating the schema detaches it
-         * from its pg_init_privs row, but an empty destination database
-         * starts with this ACL nonetheless.  Second, we support dump/reload
-         * of public schema ownership changes.  ALTER SCHEMA OWNER filters
-         * nspacl through aclnewowner(), but initprivs continues to reflect
-         * the initial owner.  Hence, synthesize the value that nspacl will
-         * have after the restore's ALTER SCHEMA OWNER.  Third, this makes the
-         * destination database match the source's ACL, even if the latter was
-         * an initdb-default ACL, which changed in v15.  An upgrade pulls in
-         * changes to most system object ACLs that the DBA had not customized.
-         * We've made the public schema depart from that, because changing its
-         * ACL so easily breaks applications.
-         */
-        buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
-                        init_racl_subquery, "n.nspacl", "n.nspowner",
-                        "CASE WHEN n.nspname = 'public' THEN array["
-                        "  format('%s=UC/%s', "
-                        "         n.nspowner::regrole, n.nspowner::regrole),"
-                        "  format('=U/%s', n.nspowner::regrole)]::aclitem[] "
-                        "ELSE pip.initprivs END",
-                        "'n'", dopt->binary_upgrade);
-
+    if (fout->remoteVersion >= 90200)
         appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
                           "n.nspowner, "
                           "(%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 = 'pg_namespace'::regclass "
-                          "AND pip.objsubid = 0",
-                          username_subquery,
-                          acl_subquery->data,
-                          racl_subquery->data,
-                          init_acl_subquery->data,
-                          init_racl_subquery->data);
-
-        appendPQExpBufferStr(query, ") ");
-
-        destroyPQExpBuffer(acl_subquery);
-        destroyPQExpBuffer(racl_subquery);
-        destroyPQExpBuffer(init_acl_subquery);
-        destroyPQExpBuffer(init_racl_subquery);
-    }
+                          "n.nspacl, "
+                          "acldefault('n', n.nspowner) AS acldefault "
+                          "FROM pg_namespace n",
+                          username_subquery);
     else
         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, nspowner, "
                           "(%s nspowner) AS rolname, "
-                          "nspacl, NULL as rnspacl, "
-                          "NULL AS initnspacl, NULL as initrnspacl "
+                          "nspacl, NULL AS acldefault "
                           "FROM pg_namespace",
                           username_subquery);

@@ -5097,9 +4991,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
     i_nspowner = PQfnumber(res, "nspowner");
     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");
+    i_acldefault = PQfnumber(res, "acldefault");

     for (i = 0; i < ntups; i++)
     {
@@ -5108,23 +5000,61 @@ getNamespaces(Archive *fout, int *numNamespaces)
         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
         AssignDumpId(&nsinfo[i].dobj);
         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
+        nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
+        nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        nsinfo[i].dacl.privtype = 0;
+        nsinfo[i].dacl.initprivs = NULL;
         nsinfo[i].nspowner = atooid(PQgetvalue(res, i, i_nspowner));
         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], fout);

         /* Mark whether namespace has an ACL */
-        if (!(PQgetisnull(res, i, i_nspacl) &&
-              PQgetisnull(res, i, i_rnspacl) &&
-              PQgetisnull(res, i, i_initnspacl) &&
-              PQgetisnull(res, i, i_initrnspacl)))
+        if (!PQgetisnull(res, i, i_nspacl))
+            nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
+
+        /*
+         * We ignore any pg_init_privs.initprivs entry for the public schema
+         * and assume a predetermined default, for several reasons.  First,
+         * dropping and recreating the schema removes its pg_init_privs entry,
+         * but an empty destination database starts with this ACL nonetheless.
+         * Second, we support dump/reload of public schema ownership changes.
+         * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
+         * initprivs continues to reflect the initial owner.  Hence,
+         * synthesize the value that nspacl will have after the restore's
+         * ALTER SCHEMA OWNER.  Third, this makes the destination database
+         * match the source's ACL, even if the latter was an initdb-default
+         * ACL, which changed in v15.  An upgrade pulls in changes to most
+         * system object ACLs that the DBA had not customized.  We've made the
+         * public schema depart from that, because changing its ACL so easily
+         * breaks applications.
+         */
+        if (strcmp(nsinfo[i].dobj.name, "public") == 0)
+        {
+            PQExpBuffer aclarray = createPQExpBuffer();
+            PQExpBuffer aclitem = createPQExpBuffer();
+
+            /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
+            appendPQExpBufferChar(aclarray, '{');
+            quoteAclUserName(aclitem, nsinfo[i].rolname);
+            appendPQExpBufferStr(aclitem, "=UC/");
+            quoteAclUserName(aclitem, nsinfo[i].rolname);
+            appendPGArray(aclarray, aclitem->data);
+            resetPQExpBuffer(aclitem);
+            appendPQExpBufferStr(aclitem, "=U/");
+            quoteAclUserName(aclitem, nsinfo[i].rolname);
+            appendPGArray(aclarray, aclitem->data);
+            appendPQExpBufferChar(aclarray, '}');
+
+            nsinfo[i].dacl.privtype = 'i';
+            nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;

+            destroyPQExpBuffer(aclarray);
+            destroyPQExpBuffer(aclitem);
+        }
+
         if (strlen(nsinfo[i].rolname) == 0)
             pg_log_warning("owner of schema \"%s\" appears to be invalid",
                            nsinfo[i].dobj.name);
@@ -5247,7 +5177,6 @@ getExtensions(Archive *fout, int *numExtensions)
 TypeInfo *
 getTypes(Archive *fout, int *numTypes)
 {
-    DumpOptions *dopt = fout->dopt;
     PGresult   *res;
     int            ntups;
     int            i;
@@ -5259,9 +5188,7 @@ 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_acldefault;
     int            i_rolname;
     int            i_typelem;
     int            i_typrelid;
@@ -5285,52 +5212,11 @@ getTypes(Archive *fout, int *numTypes)
      * cost of the subselect probe for all standard types.  This would have to
      * be revisited if the backend ever allows renaming of array types.
      */
-
-    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",
-                        "pip.initprivs", "'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.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 = 'pg_type'::regclass "
-                          "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)
+    if (fout->remoteVersion >= 90200)
     {
         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-                          "typnamespace, typacl, NULL as rtypacl, "
-                          "NULL AS inittypacl, NULL AS initrtypacl, "
+                          "typnamespace, typacl, "
+                          "acldefault('T', typowner) AS acldefault, "
                           "(%s typowner) AS rolname, "
                           "typelem, typrelid, "
                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
@@ -5344,8 +5230,7 @@ getTypes(Archive *fout, int *numTypes)
     else if (fout->remoteVersion >= 80300)
     {
         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-                          "typnamespace, NULL AS typacl, NULL as rtypacl, "
-                          "NULL AS inittypacl, NULL AS initrtypacl, "
+                          "typnamespace, NULL AS typacl, NULL AS acldefault, "
                           "(%s typowner) AS rolname, "
                           "typelem, typrelid, "
                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
@@ -5359,8 +5244,7 @@ getTypes(Archive *fout, int *numTypes)
     else
     {
         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
-                          "typnamespace, NULL AS typacl, NULL as rtypacl, "
-                          "NULL AS inittypacl, NULL AS initrtypacl, "
+                          "typnamespace, NULL AS typacl, NULL AS acldefault, "
                           "(%s typowner) AS rolname, "
                           "typelem, typrelid, "
                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
@@ -5382,9 +5266,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_inittypacl = PQfnumber(res, "inittypacl");
-    i_initrtypacl = PQfnumber(res, "initrtypacl");
+    i_acldefault = PQfnumber(res, "acldefault");
     i_rolname = PQfnumber(res, "rolname");
     i_typelem = PQfnumber(res, "typelem");
     i_typrelid = PQfnumber(res, "typrelid");
@@ -5402,12 +5284,12 @@ getTypes(Archive *fout, int *numTypes)
         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
         tyinfo[i].dobj.namespace =
             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
+        tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
+        tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        tyinfo[i].dacl.privtype = 0;
+        tyinfo[i].dacl.initprivs = NULL;
         tyinfo[i].ftypname = NULL;    /* may get filled later */
         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);
@@ -5433,10 +5315,7 @@ getTypes(Archive *fout, int *numTypes)
         selectDumpableType(&tyinfo[i], fout);

         /* Mark whether type has an ACL */
-        if (!(PQgetisnull(res, i, i_typacl) &&
-              PQgetisnull(res, i, i_rtypacl) &&
-              PQgetisnull(res, i, i_inittypacl) &&
-              PQgetisnull(res, i, i_initrtypacl)))
+        if (!PQgetisnull(res, i, i_typacl))
             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;

         /*
@@ -5963,9 +5842,7 @@ getAggregates(Archive *fout, int *numAggs)
     int            i_proargtypes;
     int            i_rolname;
     int            i_aggacl;
-    int            i_raggacl;
-    int            i_initaggacl;
-    int            i_initraggacl;
+    int            i_acldefault;

     /*
      * Find all interesting aggregates.  See comment in getFuncs() for the
@@ -5973,16 +5850,8 @@ getAggregates(Archive *fout, int *numAggs)
      */
     if (fout->remoteVersion >= 90600)
     {
-        PQExpBuffer acl_subquery = createPQExpBuffer();
-        PQExpBuffer racl_subquery = createPQExpBuffer();
-        PQExpBuffer initacl_subquery = createPQExpBuffer();
-        PQExpBuffer initracl_subquery = createPQExpBuffer();
         const char *agg_check;

-        buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
-                        initracl_subquery, "p.proacl", "p.proowner",
-                        "pip.initprivs", "'f'", dopt->binary_upgrade);
-
         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
                      : "p.proisagg");

@@ -5991,10 +5860,8 @@ getAggregates(Archive *fout, int *numAggs)
                           "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 "
+                          "p.proacl AS aggacl, "
+                          "acldefault('f', p.proowner) AS acldefault "
                           "FROM pg_proc p "
                           "LEFT JOIN pg_init_privs pip ON "
                           "(p.oid = pip.objoid "
@@ -6006,10 +5873,6 @@ getAggregates(Archive *fout, int *numAggs)
                           "WHERE nspname = 'pg_catalog') OR "
                           "p.proacl IS DISTINCT FROM pip.initprivs",
                           username_subquery,
-                          acl_subquery->data,
-                          racl_subquery->data,
-                          initacl_subquery->data,
-                          initracl_subquery->data,
                           agg_check);
         if (dopt->binary_upgrade)
             appendPQExpBufferStr(query,
@@ -6019,11 +5882,29 @@ getAggregates(Archive *fout, int *numAggs)
                                  "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 >= 90200)
+    {
+        appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
+                          "pronamespace AS aggnamespace, "
+                          "pronargs, proargtypes, "
+                          "(%s proowner) AS rolname, "
+                          "proacl AS aggacl, "
+                          "acldefault('f', proowner) AS acldefault "
+                          "FROM pg_proc p "
+                          "WHERE proisagg AND ("
+                          "pronamespace != "
+                          "(SELECT oid FROM pg_namespace "
+                          "WHERE nspname = 'pg_catalog')",
+                          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)
     {
@@ -6032,8 +5913,7 @@ getAggregates(Archive *fout, int *numAggs)
                           "pronargs, proargtypes, "
                           "(%s proowner) AS rolname, "
                           "proacl AS aggacl, "
-                          "NULL AS raggacl, "
-                          "NULL AS initaggacl, NULL AS initraggacl "
+                          "NULL AS acldefault "
                           "FROM pg_proc p "
                           "WHERE proisagg AND ("
                           "pronamespace != "
@@ -6057,8 +5937,7 @@ getAggregates(Archive *fout, int *numAggs)
                           "proargtypes, "
                           "(%s proowner) AS rolname, "
                           "proacl AS aggacl, "
-                          "NULL AS raggacl, "
-                          "NULL AS initaggacl, NULL AS initraggacl "
+                          "NULL AS acldefault "
                           "FROM pg_proc "
                           "WHERE proisagg "
                           "AND pronamespace != "
@@ -6081,9 +5960,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");
-    i_initaggacl = PQfnumber(res, "initaggacl");
-    i_initraggacl = PQfnumber(res, "initraggacl");
+    i_acldefault = PQfnumber(res, "acldefault");

     for (i = 0; i < ntups; i++)
     {
@@ -6094,16 +5971,16 @@ getAggregates(Archive *fout, int *numAggs)
         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
         agginfo[i].aggfn.dobj.namespace =
             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
+        agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
+        agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        agginfo[i].aggfn.dacl.privtype = 0;
+        agginfo[i].aggfn.dacl.initprivs = NULL;
         agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
         if (strlen(agginfo[i].aggfn.rolname) == 0)
             pg_log_warning("owner of aggregate function \"%s\" appears to be invalid",
                            agginfo[i].aggfn.dobj.name);
         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;
@@ -6119,10 +5996,7 @@ getAggregates(Archive *fout, int *numAggs)
         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);

         /* Mark whether aggregate has an ACL */
-        if (!(PQgetisnull(res, i, i_aggacl) &&
-              PQgetisnull(res, i, i_raggacl) &&
-              PQgetisnull(res, i, i_initaggacl) &&
-              PQgetisnull(res, i, i_initraggacl)))
+        if (!PQgetisnull(res, i, i_aggacl))
             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
     }

@@ -6159,9 +6033,7 @@ getFuncs(Archive *fout, int *numFuncs)
     int            i_proargtypes;
     int            i_prorettype;
     int            i_proacl;
-    int            i_rproacl;
-    int            i_initproacl;
-    int            i_initrproacl;
+    int            i_acldefault;

     /*
      * Find all interesting functions.  This is a bit complicated:
@@ -6183,30 +6055,20 @@ getFuncs(Archive *fout, int *numFuncs)
      * to gather the information about them, though they won't be dumped if
      * they are built-in.  Also, in 9.6 and up, include functions in
      * pg_catalog if they have an ACL different from what's shown in
-     * pg_init_privs.
+     * pg_init_privs (so we have to join to pg_init_privs; annoying).
      */
     if (fout->remoteVersion >= 90600)
     {
-        PQExpBuffer acl_subquery = createPQExpBuffer();
-        PQExpBuffer racl_subquery = createPQExpBuffer();
-        PQExpBuffer initacl_subquery = createPQExpBuffer();
-        PQExpBuffer initracl_subquery = createPQExpBuffer();
         const char *not_agg_check;

-        buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
-                        initracl_subquery, "p.proacl", "p.proowner",
-                        "pip.initprivs", "'f'", dopt->binary_upgrade);
-
         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
                          : "NOT p.proisagg");

         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.proacl, "
+                          "acldefault('f', p.proowner) AS acldefault, "
                           "p.pronamespace, "
                           "(%s p.proowner) AS rolname "
                           "FROM pg_proc p "
@@ -6229,10 +6091,6 @@ getFuncs(Archive *fout, int *numFuncs)
                           "\n  WHERE pg_transform.oid > %u AND "
                           "\n  (p.oid = pg_transform.trffromsql"
                           "\n  OR p.oid = pg_transform.trftosql))",
-                          acl_subquery->data,
-                          racl_subquery->data,
-                          initacl_subquery->data,
-                          initracl_subquery->data,
                           username_subquery,
                           not_agg_check,
                           g_last_builtin_oid,
@@ -6247,23 +6105,23 @@ getFuncs(Archive *fout, int *numFuncs)
         appendPQExpBufferStr(query,
                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
         appendPQExpBufferChar(query, ')');
-
-        destroyPQExpBuffer(acl_subquery);
-        destroyPQExpBuffer(racl_subquery);
-        destroyPQExpBuffer(initacl_subquery);
-        destroyPQExpBuffer(initracl_subquery);
     }
     else
     {
+        const char *acldefault_call;
+
+        acldefault_call = (fout->remoteVersion >= 90200 ?
+                           "acldefault('f', proowner)" : "NULL");
+
         appendPQExpBuffer(query,
                           "SELECT tableoid, oid, proname, prolang, "
                           "pronargs, proargtypes, prorettype, proacl, "
-                          "NULL as rproacl, "
-                          "NULL as initproacl, NULL AS initrproacl, "
+                          "%s AS acldefault, "
                           "pronamespace, "
                           "(%s proowner) AS rolname "
                           "FROM pg_proc p "
                           "WHERE NOT proisagg",
+                          acldefault_call,
                           username_subquery);
         if (fout->remoteVersion >= 90200)
             appendPQExpBufferStr(query,
@@ -6316,9 +6174,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");
-    i_initproacl = PQfnumber(res, "initproacl");
-    i_initrproacl = PQfnumber(res, "initrproacl");
+    i_acldefault = PQfnumber(res, "acldefault");

     for (i = 0; i < ntups; i++)
     {
@@ -6329,13 +6185,13 @@ getFuncs(Archive *fout, int *numFuncs)
         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
         finfo[i].dobj.namespace =
             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
+        finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
+        finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        finfo[i].dacl.privtype = 0;
+        finfo[i].dacl.initprivs = NULL;
         finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
         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;
@@ -6350,10 +6206,7 @@ getFuncs(Archive *fout, int *numFuncs)
         selectDumpableObject(&(finfo[i].dobj), fout);

         /* Mark whether function has an ACL */
-        if (!(PQgetisnull(res, i, i_proacl) &&
-              PQgetisnull(res, i, i_rproacl) &&
-              PQgetisnull(res, i, i_initproacl) &&
-              PQgetisnull(res, i, i_initrproacl)))
+        if (!PQgetisnull(res, i, i_proacl))
             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;

         if (strlen(finfo[i].rolname) == 0)
@@ -6418,10 +6271,7 @@ getTables(Archive *fout, int *numTables)
     int            i_amname;
     int            i_is_identity_sequence;
     int            i_relacl;
-    int            i_rrelacl;
-    int            i_initrelacl;
-    int            i_initrrelacl;
-    int            i_changed_acl;
+    int            i_acldefault;
     int            i_partkeydef;
     int            i_ispartition;
     int            i_partbound;
@@ -6562,67 +6412,14 @@ getTables(Archive *fout, int *numTables)
         appendPQExpBufferStr(query,
                              "false AS is_identity_sequence, ");

-    if (fout->remoteVersion >= 90600)
-    {
-        PQExpBuffer acl_subquery = createPQExpBuffer();
-        PQExpBuffer racl_subquery = createPQExpBuffer();
-        PQExpBuffer initacl_subquery = createPQExpBuffer();
-        PQExpBuffer initracl_subquery = createPQExpBuffer();
-        PQExpBuffer attacl_subquery = createPQExpBuffer();
-        PQExpBuffer attracl_subquery = createPQExpBuffer();
-        PQExpBuffer attinitacl_subquery = createPQExpBuffer();
-        PQExpBuffer attinitracl_subquery = createPQExpBuffer();
-
-        buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
-                        initracl_subquery, "c.relacl", "c.relowner",
-                        "pip.initprivs",
-                        "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
-                        " THEN 's' ELSE 'r' END::\"char\"",
-                        dopt->binary_upgrade);
-
-        buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
-                        attinitracl_subquery, "at.attacl", "c.relowner",
-                        "pip.initprivs", "'c'", dopt->binary_upgrade);
-
-        appendPQExpBuffer(query,
-                          "%s AS relacl, %s as rrelacl, "
-                          "%s AS initrelacl, %s as initrrelacl, ",
-                          acl_subquery->data,
-                          racl_subquery->data,
-                          initacl_subquery->data,
-                          initracl_subquery->data);
-
-        appendPQExpBuffer(query,
-                          "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 "
-                          "OR %s IS NOT NULL "
-                          "OR %s IS NOT NULL"
-                          "))"
-                          "AS changed_acl, ",
-                          attacl_subquery->data,
-                          attracl_subquery->data,
-                          attinitacl_subquery->data,
-                          attinitracl_subquery->data);
-
-        destroyPQExpBuffer(acl_subquery);
-        destroyPQExpBuffer(racl_subquery);
-        destroyPQExpBuffer(initacl_subquery);
-        destroyPQExpBuffer(initracl_subquery);
-        destroyPQExpBuffer(attacl_subquery);
-        destroyPQExpBuffer(attracl_subquery);
-        destroyPQExpBuffer(attinitacl_subquery);
-        destroyPQExpBuffer(attinitracl_subquery);
-    }
+    if (fout->remoteVersion >= 90200)
+        appendPQExpBufferStr(query,
+                             "c.relacl, "
+                             "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
+                             " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, ");
     else
         appendPQExpBufferStr(query,
-                             "c.relacl, NULL as rrelacl, "
-                             "NULL AS initrelacl, NULL AS initrrelacl, "
-                             "false AS changed_acl, ");
+                             "c.relacl, NULL AS acldefault, ");

     if (fout->remoteVersion >= 100000)
         appendPQExpBufferStr(query,
@@ -6644,22 +6441,16 @@ getTables(Archive *fout, int *numTables)
                          "\nFROM pg_class c\n"
                          "LEFT JOIN pg_depend d ON "
                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
-                         "d.classid = c.tableoid AND d.objid = c.oid AND "
+                         "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
                          "d.objsubid = 0 AND "
-                         "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i'))\n"
+                         "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");

     /*
-     * In 9.6 and up, left join to pg_init_privs to detect if any privileges
-     * are still as-set-at-init, in which case we won't dump out ACL commands
-     * for those.  We also are interested in the amname as of 9.6.
+     * In 9.6 and up, left join to pg_am to pick up the amname.
      */
     if (fout->remoteVersion >= 90600)
         appendPQExpBufferStr(query,
-                             "LEFT JOIN pg_init_privs pip ON "
-                             "(c.oid = pip.objoid "
-                             "AND pip.classoid = 'pg_class'::regclass "
-                             "AND pip.objsubid = 0)\n"
                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");

     /*
@@ -6671,7 +6462,9 @@ getTables(Archive *fout, int *numTables)
      */
     if (fout->remoteVersion >= 80200)
         appendPQExpBufferStr(query,
-                             "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> "
CppAsString2(RELKIND_PARTITIONED_TABLE)")\n"); 
+                             "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
+                             " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
+                             " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");

     /*
      * Restrict to interesting relkinds (in particular, not indexes).  Not all
@@ -6745,10 +6538,7 @@ getTables(Archive *fout, int *numTables)
     i_amname = PQfnumber(res, "amname");
     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
     i_relacl = PQfnumber(res, "relacl");
-    i_rrelacl = PQfnumber(res, "rrelacl");
-    i_initrelacl = PQfnumber(res, "initrelacl");
-    i_initrrelacl = PQfnumber(res, "initrrelacl");
-    i_changed_acl = PQfnumber(res, "changed_acl");
+    i_acldefault = PQfnumber(res, "acldefault");
     i_partkeydef = PQfnumber(res, "partkeydef");
     i_ispartition = PQfnumber(res, "ispartition");
     i_partbound = PQfnumber(res, "partbound");
@@ -6777,6 +6567,10 @@ getTables(Archive *fout, int *numTables)
         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
         tblinfo[i].dobj.namespace =
             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
+        tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
+        tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        tblinfo[i].dacl.privtype = 0;
+        tblinfo[i].dacl.initprivs = NULL;
         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
         tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
@@ -6823,10 +6617,6 @@ getTables(Archive *fout, int *numTables)
         else
             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
-        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].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
         tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
@@ -6862,23 +6652,10 @@ getTables(Archive *fout, int *numTables)
         /* Tables have data */
         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;

-        /*
-         * Mark whether table has an ACL.
-         *
-         * 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))
+        /* Mark whether table has an ACL */
+        if (!PQgetisnull(res, i, i_relacl))
             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
+        tblinfo[i].hascolumnACLs = false;    /* may get set later */

         /*
          * Read-lock target tables to make sure they aren't DROPPED or altered
@@ -8161,7 +7938,6 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
 ProcLangInfo *
 getProcLangs(Archive *fout, int *numProcLangs)
 {
-    DumpOptions *dopt = fout->dopt;
     PGresult   *res;
     int            ntups;
     int            i;
@@ -8175,56 +7951,30 @@ 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_acldefault;
     int            i_lanowner;

-    if (fout->remoteVersion >= 90600)
+    if (fout->remoteVersion >= 90200)
     {
-        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",
-                        "pip.initprivs", "'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 = 'pg_language'::regclass "
-                          "AND pip.objsubid = 0) "
-                          "WHERE l.lanispl "
-                          "ORDER BY l.oid",
-                          acl_subquery->data,
-                          racl_subquery->data,
-                          initacl_subquery->data,
-                          initracl_subquery->data,
+        /* acldefault() exists */
+        appendPQExpBuffer(query, "SELECT tableoid, oid, "
+                          "lanname, lanpltrusted, lanplcallfoid, "
+                          "laninline, lanvalidator, "
+                          "lanacl, "
+                          "acldefault('l', lanowner) AS acldefault, "
+                          "(%s lanowner) AS lanowner "
+                          "FROM pg_language "
+                          "WHERE lanispl "
+                          "ORDER BY oid",
                           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, NULL AS rlanacl, "
-                          "NULL AS initlanacl, NULL AS initrlanacl, "
+                          "laninline, lanvalidator, "
+                          "lanacl, NULL AS acldefault, "
                           "(%s lanowner) AS lanowner "
                           "FROM pg_language "
                           "WHERE lanispl "
@@ -8237,8 +7987,7 @@ 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 acldefault, "
                           "(%s lanowner) AS lanowner "
                           "FROM pg_language "
                           "WHERE lanispl "
@@ -8251,8 +8000,7 @@ 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 acldefault, "
                           "(%s '10') AS lanowner "
                           "FROM pg_language "
                           "WHERE lanispl "
@@ -8265,8 +8013,7 @@ 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 acldefault, "
                           "(%s '1') AS lanowner "
                           "FROM pg_language "
                           "WHERE lanispl "
@@ -8290,9 +8037,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_initlanacl = PQfnumber(res, "initlanacl");
-    i_initrlanacl = PQfnumber(res, "initrlanacl");
+    i_acldefault = PQfnumber(res, "acldefault");
     i_lanowner = PQfnumber(res, "lanowner");

     for (i = 0; i < ntups; i++)
@@ -8303,24 +8048,21 @@ getProcLangs(Archive *fout, int *numProcLangs)
         AssignDumpId(&planginfo[i].dobj);

         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
+        planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
+        planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        planginfo[i].dacl.privtype = 0;
+        planginfo[i].dacl.initprivs = NULL;
         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
         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]), fout);

         /* Mark whether language has an ACL */
-        if (!(PQgetisnull(res, i, i_lanacl) &&
-              PQgetisnull(res, i, i_rlanacl) &&
-              PQgetisnull(res, i, i_initlanacl) &&
-              PQgetisnull(res, i, i_initrlanacl)))
+        if (!PQgetisnull(res, i, i_lanacl))
             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
     }

@@ -9371,7 +9113,6 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
 FdwInfo *
 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 {
-    DumpOptions *dopt = fout->dopt;
     PGresult   *res;
     int            ntups;
     int            i;
@@ -9384,9 +9125,7 @@ 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_acldefault;
     int            i_fdwoptions;

     /* Before 8.4, there are no foreign-data wrappers */
@@ -9398,46 +9137,22 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)

     query = createPQExpBuffer();

-    if (fout->remoteVersion >= 90600)
+    if (fout->remoteVersion >= 90200)
     {
-        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",
-                        "pip.initprivs", "'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, "
+        appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
+                          "(%s fdwowner) AS rolname, "
+                          "fdwhandler::pg_catalog.regproc, "
+                          "fdwvalidator::pg_catalog.regproc, "
+                          "fdwacl, "
+                          "acldefault('F', fdwowner) AS acldefault, "
                           "array_to_string(ARRAY("
                           "SELECT quote_ident(option_name) || ' ' || "
                           "quote_literal(option_value) "
-                          "FROM pg_options_to_table(f.fdwoptions) "
+                          "FROM pg_options_to_table(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 = 'pg_foreign_data_wrapper'::regclass "
-                          "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);
+                          "FROM pg_foreign_data_wrapper",
+                          username_subquery);
     }
     else if (fout->remoteVersion >= 90100)
     {
@@ -9445,8 +9160,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
                           "(%s fdwowner) AS rolname, "
                           "fdwhandler::pg_catalog.regproc, "
                           "fdwvalidator::pg_catalog.regproc, fdwacl, "
-                          "NULL as rfdwacl, "
-                          "NULL as initfdwacl, NULL AS initrfdwacl, "
+                          "NULL AS acldefault, "
                           "array_to_string(ARRAY("
                           "SELECT quote_ident(option_name) || ' ' || "
                           "quote_literal(option_value) "
@@ -9462,8 +9176,7 @@ 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, "
+                          "NULL AS acldefault, "
                           "array_to_string(ARRAY("
                           "SELECT quote_ident(option_name) || ' ' || "
                           "quote_literal(option_value) "
@@ -9488,9 +9201,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_initfdwacl = PQfnumber(res, "initfdwacl");
-    i_initrfdwacl = PQfnumber(res, "initrfdwacl");
+    i_acldefault = PQfnumber(res, "acldefault");
     i_fdwoptions = PQfnumber(res, "fdwoptions");

     for (i = 0; i < ntups; i++)
@@ -9501,23 +9212,20 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
         AssignDumpId(&fdwinfo[i].dobj);
         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
         fdwinfo[i].dobj.namespace = NULL;
+        fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
+        fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        fdwinfo[i].dacl.privtype = 0;
+        fdwinfo[i].dacl.initprivs = NULL;
         fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
         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), fout);

         /* Mark whether FDW has an ACL */
-        if (!(PQgetisnull(res, i, i_fdwacl) &&
-              PQgetisnull(res, i, i_rfdwacl) &&
-              PQgetisnull(res, i, i_initfdwacl) &&
-              PQgetisnull(res, i, i_initrfdwacl)))
+        if (!PQgetisnull(res, i, i_fdwacl))
             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
     }

@@ -9538,7 +9246,6 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
 ForeignServerInfo *
 getForeignServers(Archive *fout, int *numForeignServers)
 {
-    DumpOptions *dopt = fout->dopt;
     PGresult   *res;
     int            ntups;
     int            i;
@@ -9552,9 +9259,7 @@ 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_acldefault;
     int            i_srvoptions;

     /* Before 8.4, there are no foreign servers */
@@ -9566,53 +9271,27 @@ getForeignServers(Archive *fout, int *numForeignServers)

     query = createPQExpBuffer();

-    if (fout->remoteVersion >= 90600)
+    if (fout->remoteVersion >= 90200)
     {
-        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",
-                        "pip.initprivs", "'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, "
+        appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
+                          "(%s srvowner) AS rolname, "
+                          "srvfdw, srvtype, srvversion, srvacl, "
+                          "acldefault('S', srvowner) AS acldefault, "
                           "array_to_string(ARRAY("
                           "SELECT quote_ident(option_name) || ' ' || "
                           "quote_literal(option_value) "
-                          "FROM pg_options_to_table(f.srvoptions) "
+                          "FROM pg_options_to_table(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 = 'pg_foreign_server'::regclass "
-                          "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);
+                          "FROM pg_foreign_server",
+                          username_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, "
+                          "NULL AS acldefault, "
                           "array_to_string(ARRAY("
                           "SELECT quote_ident(option_name) || ' ' || "
                           "quote_literal(option_value) "
@@ -9638,9 +9317,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_initsrvacl = PQfnumber(res, "initsrvacl");
-    i_initrsrvacl = PQfnumber(res, "initrsrvacl");
+    i_acldefault = PQfnumber(res, "acldefault");
     i_srvoptions = PQfnumber(res, "srvoptions");

     for (i = 0; i < ntups; i++)
@@ -9651,15 +9328,15 @@ getForeignServers(Archive *fout, int *numForeignServers)
         AssignDumpId(&srvinfo[i].dobj);
         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
         srvinfo[i].dobj.namespace = NULL;
+        srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
+        srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        srvinfo[i].dacl.privtype = 0;
+        srvinfo[i].dacl.initprivs = NULL;
         srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
         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), fout);
@@ -9668,10 +9345,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;

         /* Mark whether server has an ACL */
-        if (!(PQgetisnull(res, i, i_srvacl) &&
-              PQgetisnull(res, i, i_rsrvacl) &&
-              PQgetisnull(res, i, i_initsrvacl) &&
-              PQgetisnull(res, i, i_initrsrvacl)))
+        if (!PQgetisnull(res, i, i_srvacl))
             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
     }

@@ -9702,9 +9376,7 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
     int            i_defaclnamespace;
     int            i_defaclobjtype;
     int            i_defaclacl;
-    int            i_rdefaclacl;
-    int            i_initdefaclacl;
-    int            i_initrdefaclacl;
+    int            i_acldefault;
     int            i,
                 ntups;

@@ -9716,13 +9388,16 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)

     query = createPQExpBuffer();

-    if (fout->remoteVersion >= 90600)
-    {
-        PQExpBuffer acl_subquery = createPQExpBuffer();
-        PQExpBuffer racl_subquery = createPQExpBuffer();
-        PQExpBuffer initacl_subquery = createPQExpBuffer();
-        PQExpBuffer initracl_subquery = createPQExpBuffer();
+    appendPQExpBuffer(query,
+                      "SELECT oid, tableoid, "
+                      "(%s defaclrole) AS defaclrole, "
+                      "defaclnamespace, "
+                      "defaclobjtype, "
+                      "defaclacl, ",
+                      username_subquery);

+    if (fout->remoteVersion >= 90200)
+    {
         /*
          * Global entries (with defaclnamespace=0) replace the hard-wired
          * default ACL for their object type.  We should dump them as deltas
@@ -9730,59 +9405,24 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
          * for interpreting the ALTER DEFAULT PRIVILEGES commands.  On the
          * other hand, non-global entries can only add privileges not revoke
          * them.  We must dump those as-is (i.e., as deltas from an empty
-         * ACL).  We implement that by passing NULL as the object type for
-         * acldefault(), which works because acldefault() is STRICT.
+         * ACL).
          *
          * We can use defaclobjtype as the object type for acldefault(),
          * except for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be
          * converted to 's'.
          */
-        buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
-                        initracl_subquery, "defaclacl", "defaclrole",
-                        "pip.initprivs",
-                        "CASE WHEN defaclnamespace = 0 THEN"
-                        "      CASE WHEN defaclobjtype = 'S' THEN 's'::\"char\""
-                        "      ELSE defaclobjtype END "
-                        "ELSE NULL END",
-                        dopt->binary_upgrade);
-
-        appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
-                          "(%s d.defaclrole) AS defaclrole, "
-                          "d.defaclnamespace, "
-                          "d.defaclobjtype, "
-                          "%s AS defaclacl, "
-                          "%s AS rdefaclacl, "
-                          "%s AS initdefaclacl, "
-                          "%s AS initrdefaclacl "
-                          "FROM pg_default_acl d "
-                          "LEFT JOIN pg_init_privs pip ON "
-                          "(d.oid = pip.objoid "
-                          "AND pip.classoid = 'pg_default_acl'::regclass "
-                          "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);
+        appendPQExpBufferStr(query,
+                             "CASE WHEN defaclnamespace = 0 THEN "
+                             "acldefault(CASE WHEN defaclobjtype = 'S' "
+                             "THEN 's'::\"char\" ELSE defaclobjtype END, "
+                             "defaclrole) ELSE '{}' END AS acldefault ");
     }
     else
-    {
-        appendPQExpBuffer(query, "SELECT oid, tableoid, "
-                          "(%s defaclrole) AS defaclrole, "
-                          "defaclnamespace, "
-                          "defaclobjtype, "
-                          "defaclacl, "
-                          "NULL AS rdefaclacl, "
-                          "NULL AS initdefaclacl, "
-                          "NULL AS initrdefaclacl "
-                          "FROM pg_default_acl",
-                          username_subquery);
-    }
+        appendPQExpBufferStr(query,
+                             "NULL AS acldefault ");
+
+    appendPQExpBufferStr(query,
+                         "FROM pg_default_acl");

     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

@@ -9797,9 +9437,7 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
     i_defaclacl = PQfnumber(res, "defaclacl");
-    i_rdefaclacl = PQfnumber(res, "rdefaclacl");
-    i_initdefaclacl = PQfnumber(res, "initdefaclacl");
-    i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
+    i_acldefault = PQfnumber(res, "acldefault");

     for (i = 0; i < ntups; i++)
     {
@@ -9817,12 +9455,12 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
         else
             daclinfo[i].dobj.namespace = NULL;

+        daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
+        daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+        daclinfo[i].dacl.privtype = 0;
+        daclinfo[i].dacl.initprivs = NULL;
         daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
-        daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
-        daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
-        daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
-        daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));

         /* Default ACLs are ACLs, of course */
         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
@@ -9838,6 +9476,126 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
     return daclinfo;
 }

+/*
+ * getAdditionalACLs
+ *
+ * We have now created all the DumpableObjects, and collected the ACL data
+ * that appears in the directly-associated catalog entries.  However, there's
+ * more ACL-related info to collect.  If any of a table's columns have ACLs,
+ * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
+ * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
+ * Also, in versions having the pg_init_privs catalog, read that and load the
+ * information into the relevant DumpableObjects.
+ */
+static void
+getAdditionalACLs(Archive *fout)
+{
+    PQExpBuffer query = createPQExpBuffer();
+    PGresult   *res;
+    int            ntups,
+                i;
+
+    /* Check for per-column ACLs */
+    if (fout->remoteVersion >= 80400)
+    {
+        appendPQExpBufferStr(query,
+                             "SELECT DISTINCT attrelid FROM pg_attribute "
+                             "WHERE attacl IS NOT NULL");
+
+        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+        ntups = PQntuples(res);
+        for (i = 0; i < ntups; i++)
+        {
+            Oid            relid = atooid(PQgetvalue(res, i, 0));
+            TableInfo  *tblinfo;
+
+            tblinfo = findTableByOid(relid);
+            /* OK to ignore tables we haven't got a DumpableObject for */
+            if (tblinfo)
+            {
+                tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
+                tblinfo->hascolumnACLs = true;
+            }
+        }
+        PQclear(res);
+    }
+
+    /* Fetch initial-privileges data */
+    if (fout->remoteVersion >= 90600)
+    {
+        printfPQExpBuffer(query,
+                          "SELECT objoid, classoid, objsubid, privtype, initprivs "
+                          "FROM pg_init_privs");
+
+        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+        ntups = PQntuples(res);
+        for (i = 0; i < ntups; i++)
+        {
+            Oid            objoid = atooid(PQgetvalue(res, i, 0));
+            Oid            classoid = atooid(PQgetvalue(res, i, 1));
+            int            objsubid = atoi(PQgetvalue(res, i, 2));
+            char        privtype = *(PQgetvalue(res, i, 3));
+            char       *initprivs = PQgetvalue(res, i, 4);
+            CatalogId    objId;
+            DumpableObject *dobj;
+
+            objId.tableoid = classoid;
+            objId.oid = objoid;
+            dobj = findObjectByCatalogId(objId);
+            /* OK to ignore entries we haven't got a DumpableObject for */
+            if (dobj)
+            {
+                /* Cope with sub-object initprivs */
+                if (objsubid != 0)
+                {
+                    if (dobj->objType == DO_TABLE)
+                    {
+                        /* For a column initpriv, set the table's ACL flags */
+                        dobj->components |= DUMP_COMPONENT_ACL;
+                        ((TableInfo *) dobj)->hascolumnACLs = true;
+                    }
+                    else
+                        pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
+                                       classoid, objoid, objsubid);
+                    continue;
+                }
+
+                /*
+                 * We ignore any pg_init_privs.initprivs entry for the public
+                 * schema, as explained in getNamespaces().
+                 */
+                if (dobj->objType == DO_NAMESPACE &&
+                    strcmp(dobj->name, "public") == 0)
+                    continue;
+
+                /* Else it had better be of a type we think has ACLs */
+                if (dobj->objType == DO_NAMESPACE ||
+                    dobj->objType == DO_TYPE ||
+                    dobj->objType == DO_FUNC ||
+                    dobj->objType == DO_AGG ||
+                    dobj->objType == DO_TABLE ||
+                    dobj->objType == DO_PROCLANG ||
+                    dobj->objType == DO_FDW ||
+                    dobj->objType == DO_FOREIGN_SERVER)
+                {
+                    DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
+
+                    daobj->dacl.privtype = privtype;
+                    daobj->dacl.initprivs = pstrdup(initprivs);
+                }
+                else
+                    pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
+                                   classoid, objoid, objsubid);
+            }
+        }
+        PQclear(res);
+    }
+
+    destroyPQExpBuffer(query);
+}
+
 /*
  * dumpCommentExtended --
  *
@@ -10490,8 +10248,7 @@ dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
                 qnspname, NULL, NULL,
-                nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
-                nspinfo->initnspacl, nspinfo->initrnspacl);
+                nspinfo->rolname, &nspinfo->dacl);

     free(qnspname);

@@ -10782,8 +10539,7 @@ dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
                 qtypname, NULL,
                 tyinfo->dobj.namespace->dobj.name,
-                tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
-                tyinfo->inittypacl, tyinfo->initrtypacl);
+                tyinfo->rolname, &tyinfo->dacl);

     PQclear(res);
     destroyPQExpBuffer(q);
@@ -10922,8 +10678,7 @@ dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
                 qtypname, NULL,
                 tyinfo->dobj.namespace->dobj.name,
-                tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
-                tyinfo->inittypacl, tyinfo->initrtypacl);
+                tyinfo->rolname, &tyinfo->dacl);

     PQclear(res);
     destroyPQExpBuffer(q);
@@ -10994,8 +10749,7 @@ dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
                 qtypname, NULL,
                 tyinfo->dobj.namespace->dobj.name,
-                tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
-                tyinfo->inittypacl, tyinfo->initrtypacl);
+                tyinfo->rolname, &tyinfo->dacl);

     destroyPQExpBuffer(q);
     destroyPQExpBuffer(delq);
@@ -11254,8 +11008,7 @@ dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
                 qtypname, NULL,
                 tyinfo->dobj.namespace->dobj.name,
-                tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
-                tyinfo->inittypacl, tyinfo->initrtypacl);
+                tyinfo->rolname, &tyinfo->dacl);

     PQclear(res);
     destroyPQExpBuffer(q);
@@ -11411,8 +11164,7 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo)
         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
                 qtypname, NULL,
                 tyinfo->dobj.namespace->dobj.name,
-                tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
-                tyinfo->inittypacl, tyinfo->initrtypacl);
+                tyinfo->rolname, &tyinfo->dacl);

     /* Dump any per-constraint comments */
     for (i = 0; i < tyinfo->nDomChecks; i++)
@@ -11633,8 +11385,7 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
                 qtypname, NULL,
                 tyinfo->dobj.namespace->dobj.name,
-                tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
-                tyinfo->inittypacl, tyinfo->initrtypacl);
+                tyinfo->rolname, &tyinfo->dacl);

     PQclear(res);
     destroyPQExpBuffer(q);
@@ -11932,8 +11683,7 @@ dumpProcLang(Archive *fout, const ProcLangInfo *plang)
     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
                 qlanname, NULL, NULL,
-                plang->lanowner, plang->lanacl, plang->rlanacl,
-                plang->initlanacl, plang->initrlanacl);
+                plang->lanowner, &plang->dacl);

     free(qlanname);

@@ -12569,8 +12319,7 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
                 funcsig, NULL,
                 finfo->dobj.namespace->dobj.name,
-                finfo->rolname, finfo->proacl, finfo->rproacl,
-                finfo->initproacl, finfo->initrproacl);
+                finfo->rolname, &finfo->dacl);

     PQclear(res);

@@ -14474,9 +14223,7 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
                 "FUNCTION", aggsig, NULL,
                 agginfo->aggfn.dobj.namespace->dobj.name,
-                agginfo->aggfn.rolname, agginfo->aggfn.proacl,
-                agginfo->aggfn.rproacl,
-                agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
+                agginfo->aggfn.rolname, &agginfo->aggfn.dacl);

     free(aggsig);
     if (aggfullsig)
@@ -14875,9 +14622,7 @@ dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
-                NULL, fdwinfo->rolname,
-                fdwinfo->fdwacl, fdwinfo->rfdwacl,
-                fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
+                NULL, fdwinfo->rolname, &fdwinfo->dacl);

     free(qfdwname);

@@ -14964,9 +14709,7 @@ dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
                 "FOREIGN SERVER", qsrvname, NULL,
-                NULL, srvinfo->rolname,
-                srvinfo->srvacl, srvinfo->rsrvacl,
-                srvinfo->initsrvacl, srvinfo->initrsrvacl);
+                NULL, srvinfo->rolname, &srvinfo->dacl);

     /* Dump user mappings */
     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
@@ -15130,15 +14873,13 @@ dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
     if (!buildDefaultACLCommands(type,
                                  daclinfo->dobj.namespace != NULL ?
                                  daclinfo->dobj.namespace->dobj.name : NULL,
-                                 daclinfo->defaclacl,
-                                 daclinfo->rdefaclacl,
-                                 daclinfo->initdefaclacl,
-                                 daclinfo->initrdefaclacl,
+                                 daclinfo->dacl.acl,
+                                 daclinfo->dacl.acldefault,
                                  daclinfo->defaclrole,
                                  fout->remoteVersion,
                                  q))
         fatal("could not parse default ACL list (%s)",
-              daclinfo->defaclacl);
+              daclinfo->dacl.acl);

     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
@@ -15168,20 +14909,7 @@ dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
  *        (Currently we assume that subname is only provided for table columns.)
  * 'nspname' is the namespace the object is in (NULL if none).
  * 'owner' is the owner, NULL if there is no owner (for languages).
- * 'acls' contains the ACL string of the object from the appropriate system
- *         catalog field; it will be passed to buildACLCommands for building the
- *         appropriate GRANT commands.
- * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
- *         object; it will be passed to buildACLCommands for building the
- *         appropriate REVOKE commands.
- * 'initacls' In binary-upgrade mode, ACL string of the object's initial
- *         privileges, to be recorded into pg_init_privs
- * 'initracls' In binary-upgrade mode, ACL string of the object's
- *         revoked-from-default privileges, to be recorded into pg_init_privs
- *
- * NB: initacls/initracls are needed because extensions can set privileges on
- * an object during the extension's script file and we record those into
- * pg_init_privs as that object's initial privileges.
+ * 'dacl' is the DumpableAcl struct fpr the object.
  *
  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
  * no ACL entry was created.
@@ -15191,11 +14919,15 @@ static DumpId
 dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
         const char *type, const char *name, const char *subname,
         const char *nspname, const char *owner,
-        const char *acls, const char *racls,
-        const char *initacls, const char *initracls)
+        const DumpableAcl *dacl)
 {
     DumpId        aclDumpId = InvalidDumpId;
     DumpOptions *dopt = fout->dopt;
+    const char *acls = dacl->acl;
+    const char *acldefault = dacl->acldefault;
+    char        privtype = dacl->privtype;
+    const char *initprivs = dacl->initprivs;
+    const char *baseacls;
     PQExpBuffer sql;

     /* Do nothing if ACL dump is not enabled */
@@ -15209,29 +14941,52 @@ dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     sql = createPQExpBuffer();

     /*
-     * 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.
+     * In binary upgrade mode, we don't run an extension's script but instead
+     * dump out the objects independently and then recreate them.  To preserve
+     * any initial privileges which were set on extension objects, we need to
+     * compute the set of GRANT and REVOKE commands necessary to get from the
+     * default privileges of an object to its initial privileges as recorded
+     * in pg_init_privs.
+     *
+     * At restore time, we apply these commands after having called
+     * binary_upgrade_set_record_init_privs(true).  That tells the backend to
+     * copy the results into pg_init_privs.  This is how we preserve the
+     * contents of that catalog across binary upgrades.
      */
-    if (strlen(initacls) != 0 || strlen(initracls) != 0)
+    if (dopt->binary_upgrade && privtype == 'e' &&
+        initprivs && *initprivs != '\0')
     {
         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
         if (!buildACLCommands(name, subname, nspname, type,
-                              initacls, initracls, owner,
+                              initprivs, acldefault, owner,
                               "", fout->remoteVersion, sql))
-            fatal("could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\"
(%s)",
-                  initacls, initracls, name, type);
+            fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
+                  initprivs, acldefault, name, type);
         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
     }

+    /*
+     * Now figure the GRANT and REVOKE commands needed to get to the object's
+     * actual current ACL, starting from the initprivs if given, else from the
+     * object-type-specific default.  Also, while buildACLCommands will assume
+     * that a NULL/empty acls string means it needn't do anything, what that
+     * actually represents is the object-type-specific default; so we need to
+     * substitute the acldefault string to get the right results in that case.
+     */
+    if (initprivs && *initprivs != '\0')
+    {
+        baseacls = initprivs;
+        if (acls == NULL || *acls == '\0')
+            acls = acldefault;
+    }
+    else
+        baseacls = acldefault;
+
     if (!buildACLCommands(name, subname, nspname, type,
-                          acls, racls, owner,
+                          acls, baseacls, owner,
                           "", fout->remoteVersion, sql))
-        fatal("could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)",
-              acls, racls, name, type);
+        fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
+              acls, baseacls, name, type);

     if (sql->len > 0)
     {
@@ -15641,8 +15396,7 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
                     objtype, namecopy, NULL,
                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-                    tbinfo->relacl, tbinfo->rrelacl,
-                    tbinfo->initrelacl, tbinfo->initrrelacl);
+                    &tbinfo->dacl);
     }

     /*
@@ -15651,7 +15405,7 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
      * miss ACLs on system columns.  Doing it this way also allows us to dump
      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
      */
-    if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
+    if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
     {
         PQExpBuffer query = createPQExpBuffer();
         PGresult   *res;
@@ -15659,55 +15413,37 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)

         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",
-                            "pip.initprivs", "'c'", dopt->binary_upgrade);
-
+            /*
+             * In principle we should call acldefault('c', relowner) to get
+             * the default ACL for a column.  However, we don't currently
+             * store the numeric OID of the relowner in TableInfo.  We could
+             * convert the owner name using regrole, but that creates a risk
+             * of failure due to concurrent role renames.  Given that the
+             * default ACL for columns is empty and is likely to stay that
+             * way, it's not worth extra cycles and risk to avoid hard-wiring
+             * that knowledge here.
+             */
             appendPQExpBuffer(query,
                               "SELECT at.attname, "
-                              "%s AS attacl, "
-                              "%s AS rattacl, "
-                              "%s AS initattacl, "
-                              "%s AS initrattacl "
+                              "at.attacl, "
+                              "'{}' AS acldefault, "
+                              "pip.privtype, pip.initprivs "
                               "FROM pg_catalog.pg_attribute at "
-                              "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
                               "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'::pg_catalog.oid AND "
                               "NOT at.attisdropped "
-                              "AND ("
-                              "%s IS NOT NULL OR "
-                              "%s IS NOT NULL OR "
-                              "%s IS NOT NULL OR "
-                              "%s IS NOT NULL)"
+                              "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
                               "ORDER BY at.attnum",
-                              acl_subquery->data,
-                              racl_subquery->data,
-                              initacl_subquery->data,
-                              initracl_subquery->data,
-                              tbinfo->dobj.catId.oid,
-                              acl_subquery->data,
-                              racl_subquery->data,
-                              initacl_subquery->data,
-                              initracl_subquery->data);
-
-            destroyPQExpBuffer(acl_subquery);
-            destroyPQExpBuffer(racl_subquery);
-            destroyPQExpBuffer(initacl_subquery);
-            destroyPQExpBuffer(initracl_subquery);
+                              tbinfo->dobj.catId.oid);
         }
         else
         {
             appendPQExpBuffer(query,
-                              "SELECT attname, attacl, NULL as rattacl, "
-                              "NULL AS initattacl, NULL AS initrattacl "
+                              "SELECT attname, attacl, '{}' AS acldefault, "
+                              "NULL AS privtype, NULL AS initprivs "
                               "FROM pg_catalog.pg_attribute "
                               "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
                               "AND attacl IS NOT NULL "
@@ -15721,11 +15457,16 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
         {
             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       *acldefault = PQgetvalue(res, i, 2);
+            char        privtype = *(PQgetvalue(res, i, 3));
+            char       *initprivs = PQgetvalue(res, i, 4);
+            DumpableAcl coldacl;
             char       *attnamecopy;

+            coldacl.acl = attacl;
+            coldacl.acldefault = acldefault;
+            coldacl.privtype = privtype;
+            coldacl.initprivs = initprivs;
             attnamecopy = pg_strdup(fmtId(attname));

             /*
@@ -15736,7 +15477,7 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
                     "TABLE", namecopy, attnamecopy,
                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
-                    attacl, rattacl, initattacl, initrattacl);
+                    &coldacl);
             free(attnamecopy);
         }
         PQclear(res);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 6e9a76103c..b21b91f8bc 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -146,16 +146,36 @@ typedef struct _dumpableObject
     int            allocDeps;        /* allocated size of dependencies[] */
 } DumpableObject;

+/*
+ * Object types that have ACLs must store them in a DumpableAcl sub-struct,
+ * which must immediately follow the DumpableObject base struct.
+ *
+ * Note: when dumping from a pre-9.2 server, which lacks the acldefault()
+ * function, acldefault will be NULL or empty.
+ */
+typedef struct _dumpableAcl
+{
+    char       *acl;            /* the object's actual ACL string */
+    char       *acldefault;        /* default ACL for the object's type & owner */
+    /* these fields come from the object's pg_init_privs entry, if any: */
+    char        privtype;        /* entry type, 'i' or 'e'; 0 if no entry */
+    char       *initprivs;        /* the object's initial ACL string, or NULL */
+} DumpableAcl;
+
+/* Generic struct that can be used to access any object type having an ACL */
+typedef struct _dumpableObjectWithAcl
+{
+    DumpableObject dobj;
+    DumpableAcl dacl;
+} DumpableObjectWithAcl;
+
 typedef struct _namespaceInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;
     bool        create;            /* CREATE SCHEMA, or just set owner? */
     Oid            nspowner;
     char       *rolname;        /* name of owner, or empty string */
-    char       *nspacl;
-    char       *rnspacl;
-    char       *initnspacl;
-    char       *initrnspacl;
 } NamespaceInfo;

 typedef struct _extensionInfo
@@ -171,6 +191,7 @@ typedef struct _extensionInfo
 typedef struct _typeInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;

     /*
      * Note: dobj.name is the raw pg_type.typname entry.  ftypname is the
@@ -179,10 +200,6 @@ typedef struct _typeInfo
      */
     char       *ftypname;
     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 */
@@ -207,15 +224,12 @@ typedef struct _shellTypeInfo
 typedef struct _funcInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;
     char       *rolname;        /* name of owner, or empty string */
     Oid            lang;
     int            nargs;
     Oid           *argtypes;
     Oid            prorettype;
-    char       *proacl;
-    char       *rproacl;
-    char       *initproacl;
-    char       *initrproacl;
 } FuncInfo;

 /* AggInfo is a superset of FuncInfo */
@@ -270,11 +284,8 @@ typedef struct _tableInfo
      * These fields are collected for every table in the database.
      */
     DumpableObject dobj;
+    DumpableAcl dacl;
     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 */
@@ -286,6 +297,7 @@ typedef struct _tableInfo
     bool        hasindex;        /* does it have any indexes? */
     bool        hasrules;        /* does it have any rules? */
     bool        hastriggers;    /* does it have any triggers? */
+    bool        hascolumnACLs;    /* do any columns have non-default ACLs? */
     bool        rowsec;            /* is row security enabled? */
     bool        forcerowsec;    /* is row security forced? */
     bool        hasoids;        /* does it have OIDs? */
@@ -478,14 +490,11 @@ typedef struct _constraintInfo
 typedef struct _procLangInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;
     bool        lanpltrusted;
     Oid            lanplcallfoid;
     Oid            laninline;
     Oid            lanvalidator;
-    char       *lanacl;
-    char       *rlanacl;
-    char       *initlanacl;
-    char       *initrlanacl;
     char       *lanowner;        /* name of owner, or empty string */
 } ProcLangInfo;

@@ -550,49 +559,37 @@ typedef struct _cfgInfo
 typedef struct _fdwInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;
     char       *rolname;
     char       *fdwhandler;
     char       *fdwvalidator;
     char       *fdwoptions;
-    char       *fdwacl;
-    char       *rfdwacl;
-    char       *initfdwacl;
-    char       *initrfdwacl;
 } FdwInfo;

 typedef struct _foreignServerInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;
     char       *rolname;
     Oid            srvfdw;
     char       *srvtype;
     char       *srvversion;
-    char       *srvacl;
-    char       *rsrvacl;
-    char       *initsrvacl;
-    char       *initrsrvacl;
     char       *srvoptions;
 } ForeignServerInfo;

 typedef struct _defaultACLInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;
     char       *defaclrole;
     char        defaclobjtype;
-    char       *defaclacl;
-    char       *rdefaclacl;
-    char       *initdefaclacl;
-    char       *initrdefaclacl;
 } DefaultACLInfo;

 typedef struct _blobInfo
 {
     DumpableObject dobj;
+    DumpableAcl dacl;
     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 c29101704a..44114f3f71 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1166,55 +1166,12 @@ dumpTablespaces(PGconn *conn)
     /*
      * Get all tablespaces except built-in ones (which we assume are named
      * pg_xxx)
-     *
-     * For the tablespace ACLs, as of 9.6, we extract both the positive (as
-     * spcacl) and negative (as rspcacl) ACLs, relative to the default ACL for
-     * tablespaces, which are then passed to buildACLCommands() below.
-     *
-     * See buildACLQueries() and buildACLCommands().
-     *
-     * The order in which privileges are in the ACL string (the order they
-     * have been GRANT'd in, which the backend maintains) must be preserved to
-     * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
-     * those are dumped in the correct order.
-     *
-     * Note that we do not support initial privileges (pg_init_privs) on
-     * tablespaces, so this logic cannot make use of buildACLQueries().
      */
-    if (server_version >= 90600)
-        res = executeQuery(conn, "SELECT oid, spcname, "
-                           "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
-                           "pg_catalog.pg_tablespace_location(oid), "
-                           "(SELECT array_agg(acl ORDER BY row_n) FROM "
-                           "  (SELECT acl, row_n FROM "
-                           "     unnest(coalesce(spcacl,acldefault('t',spcowner))) "
-                           "     WITH ORDINALITY AS perm(acl,row_n) "
-                           "   WHERE NOT EXISTS ( "
-                           "     SELECT 1 "
-                           "     FROM unnest(acldefault('t',spcowner)) "
-                           "       AS init(init_acl) "
-                           "     WHERE acl = init_acl)) AS spcacls) "
-                           " AS spcacl, "
-                           "(SELECT array_agg(acl ORDER BY row_n) FROM "
-                           "  (SELECT acl, row_n FROM "
-                           "     unnest(acldefault('t',spcowner)) "
-                           "     WITH ORDINALITY AS initp(acl,row_n) "
-                           "   WHERE NOT EXISTS ( "
-                           "     SELECT 1 "
-                           "     FROM unnest(coalesce(spcacl,acldefault('t',spcowner))) "
-                           "       AS permp(orig_acl) "
-                           "     WHERE acl = orig_acl)) AS rspcacls) "
-                           " AS rspcacl, "
-                           "array_to_string(spcoptions, ', '),"
-                           "pg_catalog.shobj_description(oid, 'pg_tablespace') "
-                           "FROM pg_catalog.pg_tablespace "
-                           "WHERE spcname !~ '^pg_' "
-                           "ORDER BY 1");
-    else if (server_version >= 90200)
+    if (server_version >= 90200)
         res = executeQuery(conn, "SELECT oid, spcname, "
                            "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
                            "pg_catalog.pg_tablespace_location(oid), "
-                           "spcacl, '' as rspcacl, "
+                           "spcacl, acldefault('t', spcowner) AS acldefault, "
                            "array_to_string(spcoptions, ', '),"
                            "pg_catalog.shobj_description(oid, 'pg_tablespace') "
                            "FROM pg_catalog.pg_tablespace "
@@ -1223,7 +1180,7 @@ dumpTablespaces(PGconn *conn)
     else if (server_version >= 90000)
         res = executeQuery(conn, "SELECT oid, spcname, "
                            "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
-                           "spclocation, spcacl, '' as rspcacl, "
+                           "spclocation, spcacl, NULL AS acldefault, "
                            "array_to_string(spcoptions, ', '),"
                            "pg_catalog.shobj_description(oid, 'pg_tablespace') "
                            "FROM pg_catalog.pg_tablespace "
@@ -1232,7 +1189,7 @@ dumpTablespaces(PGconn *conn)
     else if (server_version >= 80200)
         res = executeQuery(conn, "SELECT oid, spcname, "
                            "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
-                           "spclocation, spcacl, '' as rspcacl, null, "
+                           "spclocation, spcacl, NULL AS acldefault, null, "
                            "pg_catalog.shobj_description(oid, 'pg_tablespace') "
                            "FROM pg_catalog.pg_tablespace "
                            "WHERE spcname !~ '^pg_' "
@@ -1240,7 +1197,7 @@ dumpTablespaces(PGconn *conn)
     else
         res = executeQuery(conn, "SELECT oid, spcname, "
                            "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
-                           "spclocation, spcacl, '' as rspcacl, "
+                           "spclocation, spcacl, NULL AS acldefault, "
                            "null, null "
                            "FROM pg_catalog.pg_tablespace "
                            "WHERE spcname !~ '^pg_' "
@@ -1257,7 +1214,7 @@ dumpTablespaces(PGconn *conn)
         char       *spcowner = PQgetvalue(res, i, 2);
         char       *spclocation = PQgetvalue(res, i, 3);
         char       *spcacl = PQgetvalue(res, i, 4);
-        char       *rspcacl = PQgetvalue(res, i, 5);
+        char       *acldefault = PQgetvalue(res, i, 5);
         char       *spcoptions = PQgetvalue(res, i, 6);
         char       *spccomment = PQgetvalue(res, i, 7);
         char       *fspcname;
@@ -1276,9 +1233,11 @@ dumpTablespaces(PGconn *conn)
             appendPQExpBuffer(buf, "ALTER TABLESPACE %s SET (%s);\n",
                               fspcname, spcoptions);

+        /* tablespaces can't have initprivs */
+
         if (!skip_acls &&
             !buildACLCommands(fspcname, NULL, NULL, "TABLESPACE",
-                              spcacl, rspcacl,
+                              spcacl, acldefault,
                               spcowner, "", server_version, buf))
         {
             pg_log_error("could not parse ACL list (%s) for tablespace \"%s\"",
diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c
index 3efee4e7ee..81e623602e 100644
--- a/src/fe_utils/string_utils.c
+++ b/src/fe_utils/string_utils.c
@@ -726,6 +726,69 @@ parsePGArray(const char *atext, char ***itemarray, int *nitems)
 }


+/*
+ * Append one element to the text representation of a 1-dimensional Postgres
+ * array.
+ *
+ * The caller must provide the initial '{' and closing '}' of the array.
+ * This function handles all else, including insertion of commas and
+ * quoting of values.
+ *
+ * We assume that typdelim is ','.
+ */
+void
+appendPGArray(PQExpBuffer buffer, const char *value)
+{
+    bool        needquote;
+    const char *tmp;
+
+    if (buffer->data[buffer->len - 1] != '{')
+        appendPQExpBufferChar(buffer, ',');
+
+    /* Decide if we need quotes; this should match array_out()'s choices. */
+    if (value[0] == '\0')
+        needquote = true;        /* force quotes for empty string */
+    else if (pg_strcasecmp(value, "NULL") == 0)
+        needquote = true;        /* force quotes for literal NULL */
+    else
+        needquote = false;
+
+    if (!needquote)
+    {
+        for (tmp = value; *tmp; tmp++)
+        {
+            char        ch = *tmp;
+
+            if (ch == '"' || ch == '\\' ||
+                ch == '{' || ch == '}' || ch == ',' ||
+            /* these match array_isspace(): */
+                ch == ' ' || ch == '\t' || ch == '\n' ||
+                ch == '\r' || ch == '\v' || ch == '\f')
+            {
+                needquote = true;
+                break;
+            }
+        }
+    }
+
+    if (needquote)
+    {
+        appendPQExpBufferChar(buffer, '"');
+        for (tmp = value; *tmp; tmp++)
+        {
+            char        ch = *tmp;
+
+            if (ch == '"' || ch == '\\')
+                appendPQExpBufferChar(buffer, '\\');
+            appendPQExpBufferChar(buffer, ch);
+        }
+        appendPQExpBufferChar(buffer, '"');
+    }
+    else
+        appendPQExpBufferStr(buffer, value);
+}
+
+
 /*
  * Format a reloptions array and append it to the given buffer.
  *
diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h
index caafb97d29..e12e61cddb 100644
--- a/src/include/fe_utils/string_utils.h
+++ b/src/include/fe_utils/string_utils.h
@@ -46,6 +46,7 @@ extern void appendConnStrVal(PQExpBuffer buf, const char *str);
 extern void appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname);

 extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
+extern void appendPGArray(PQExpBuffer buffer, const char *value);

 extern bool appendReloptionsArray(PQExpBuffer buffer, const char *reloptions,
                                   const char *prefix, int encoding, bool std_strings);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 75ea57266e..294f8fcbbb 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -6272,20 +6272,23 @@ getTables(Archive *fout, int *numTables)
     int            i_is_identity_sequence;
     int            i_relacl;
     int            i_acldefault;
-    int            i_partkeydef;
     int            i_ispartition;
-    int            i_partbound;

     /*
      * Find all the tables and table-like objects.
      *
+     * We must fetch all tables in this phase because otherwise we cannot
+     * correctly identify inherited columns, owned sequences, etc.
+     *
      * We include system catalogs, so that we can work if a user table is
      * defined to inherit from a system catalog (pretty weird, but...)
      *
      * Note: in this phase we should collect only a minimal amount of
      * information about each table, basically just enough to decide if it is
-     * interesting. We must fetch all tables in this phase because otherwise
-     * we cannot correctly identify inherited columns, owned sequences, etc.
+     * interesting.  In particular, since we do not yet have lock on any user
+     * table, we MUST NOT invoke any server-side data collection functions
+     * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
+     * wrong answers if any concurrent DDL is happening.
      */

     appendPQExpBuffer(query,
@@ -6379,10 +6382,10 @@ getTables(Archive *fout, int *numTables)

     if (fout->remoteVersion >= 90000)
         appendPQExpBufferStr(query,
-                             "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS
reloftype,"); 
+                             "c.reloftype, ");
     else
         appendPQExpBufferStr(query,
-                             "NULL AS reloftype, ");
+                             "0 AS reloftype, ");

     if (fout->remoteVersion >= 90100)
         appendPQExpBufferStr(query,
@@ -6423,14 +6426,10 @@ getTables(Archive *fout, int *numTables)

     if (fout->remoteVersion >= 100000)
         appendPQExpBufferStr(query,
-                             "pg_get_partkeydef(c.oid) AS partkeydef, "
-                             "c.relispartition AS ispartition, "
-                             "pg_get_expr(c.relpartbound, c.oid) AS partbound ");
+                             "c.relispartition AS ispartition ");
     else
         appendPQExpBufferStr(query,
-                             "NULL AS partkeydef, "
-                             "false AS ispartition, "
-                             "NULL AS partbound ");
+                             "false AS ispartition ");

     /*
      * Left join to pg_depend to pick up dependency info linking sequences to
@@ -6539,9 +6538,7 @@ getTables(Archive *fout, int *numTables)
     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
     i_relacl = PQfnumber(res, "relacl");
     i_acldefault = PQfnumber(res, "acldefault");
-    i_partkeydef = PQfnumber(res, "partkeydef");
     i_ispartition = PQfnumber(res, "ispartition");
-    i_partbound = PQfnumber(res, "partbound");

     if (dopt->lockWaitTimeout)
     {
@@ -6607,19 +6604,14 @@ getTables(Archive *fout, int *numTables)
         else
             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
-        if (PQgetisnull(res, i, i_reloftype))
-            tblinfo[i].reloftype = NULL;
-        else
-            tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
+        tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
         if (PQgetisnull(res, i, i_amname))
             tblinfo[i].amname = NULL;
         else
             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
-        tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
-        tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));

         /* other fields were zeroed above */

@@ -15651,12 +15643,34 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
     }
     else
     {
+        char       *partkeydef = NULL;
         char       *ftoptions = NULL;
         char       *srvname = NULL;
         char       *foreign = "";

+        /*
+         * Set reltypename, and collect any relkind-specific data that we
+         * didn't fetch during getTables().
+         */
         switch (tbinfo->relkind)
         {
+            case RELKIND_PARTITIONED_TABLE:
+                {
+                    PQExpBuffer query = createPQExpBuffer();
+                    PGresult   *res;
+
+                    reltypename = "TABLE";
+
+                    /* retrieve partition key definition */
+                    appendPQExpBuffer(query,
+                                      "SELECT pg_get_partkeydef('%u')",
+                                      tbinfo->dobj.catId.oid);
+                    res = ExecuteSqlQueryForSingleRow(fout, query->data);
+                    partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
+                    PQclear(res);
+                    destroyPQExpBuffer(query);
+                    break;
+                }
             case RELKIND_FOREIGN_TABLE:
                 {
                     PQExpBuffer query = createPQExpBuffer();
@@ -15696,6 +15710,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
                 break;
             default:
                 reltypename = "TABLE";
+                break;
         }

         numParents = tbinfo->numParents;
@@ -15717,8 +15732,10 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
          * Attach to type, if reloftype; except in case of a binary upgrade,
          * we dump the table normally and attach it to the type afterward.
          */
-        if (tbinfo->reloftype && !dopt->binary_upgrade)
-            appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
+        if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
+            appendPQExpBuffer(q, " OF %s",
+                              getFormattedTypeName(fout, tbinfo->reloftype,
+                                                   zeroIsError));

         if (tbinfo->relkind != RELKIND_MATVIEW)
         {
@@ -15756,7 +15773,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
                      * Skip column if fully defined by reloftype, except in
                      * binary upgrade
                      */
-                    if (tbinfo->reloftype && !print_default && !print_notnull &&
+                    if (OidIsValid(tbinfo->reloftype) &&
+                        !print_default && !print_notnull &&
                         !dopt->binary_upgrade)
                         continue;

@@ -15789,7 +15807,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
                      * table ('OF type_name'), but in binary-upgrade mode,
                      * print it in that case too.
                      */
-                    if (dopt->binary_upgrade || !tbinfo->reloftype)
+                    if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
                     {
                         appendPQExpBuffer(q, " %s",
                                           tbinfo->atttypnames[j]);
@@ -15852,7 +15870,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)

             if (actual_atts)
                 appendPQExpBufferStr(q, "\n)");
-            else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
+            else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
             {
                 /*
                  * No attributes? we must have a parenthesized attribute list,
@@ -15881,7 +15899,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
             }

             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
-                appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
+                appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);

             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
@@ -16064,12 +16082,13 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
                 }
             }

-            if (tbinfo->reloftype)
+            if (OidIsValid(tbinfo->reloftype))
             {
                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
                                   qualrelname,
-                                  tbinfo->reloftype);
+                                  getFormattedTypeName(fout, tbinfo->reloftype,
+                                                       zeroIsError));
             }
         }

@@ -16242,6 +16261,8 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
                                   tbinfo->attfdwoptions[j]);
         }                        /* end loop over columns */

+        if (partkeydef)
+            free(partkeydef);
         if (ftoptions)
             free(ftoptions);
         if (srvname)
@@ -16358,6 +16379,8 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
 {
     DumpOptions *dopt = fout->dopt;
     PQExpBuffer q;
+    PGresult   *res;
+    char       *partbound;

     /* Do nothing in data-only dump */
     if (dopt->dataOnly)
@@ -16368,14 +16391,23 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)

     q = createPQExpBuffer();

-    /* Perform ALTER TABLE on the parent */
+    /* Fetch the partition's partbound */
     appendPQExpBuffer(q,
+                      "SELECT pg_get_expr(c.relpartbound, c.oid) "
+                      "FROM pg_class c "
+                      "WHERE c.oid = '%u'",
+                      attachinfo->partitionTbl->dobj.catId.oid);
+    res = ExecuteSqlQueryForSingleRow(fout, q->data);
+    partbound = PQgetvalue(res, 0, 0);
+
+    /* Perform ALTER TABLE on the parent */
+    printfPQExpBuffer(q,
                       "ALTER TABLE ONLY %s ",
                       fmtQualifiedDumpable(attachinfo->parentTbl));
     appendPQExpBuffer(q,
                       "ATTACH PARTITION %s %s;\n",
                       fmtQualifiedDumpable(attachinfo->partitionTbl),
-                      attachinfo->partitionTbl->partbound);
+                      partbound);

     /*
      * There is no point in creating a drop query as the drop is done by table
@@ -16392,6 +16424,7 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
                               .section = SECTION_PRE_DATA,
                               .createStmt = q->data));

+    PQclear(res);
     destroyPQExpBuffer(q);
 }

diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index b21b91f8bc..291b880a97 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -308,7 +308,7 @@ typedef struct _tableInfo
     uint32        toast_minmxid;    /* toast table's relminmxid */
     int            ncheck;            /* # of CHECK expressions */
     Oid            reltype;        /* OID of table's composite type, if any */
-    char       *reloftype;        /* underlying type for typed table */
+    Oid            reloftype;        /* underlying type for typed table */
     Oid            foreign_server; /* foreign server oid, if applicable */
     /* these two are set only if table is a sequence owned by a column: */
     Oid            owning_tab;        /* OID of table owning sequence */
@@ -347,8 +347,6 @@ typedef struct _tableInfo
     bool       *inhNotNull;        /* true if NOT NULL is inherited */
     struct _attrDefInfo **attrdefs; /* DEFAULT expressions */
     struct _constraintInfo *checkexprs; /* CHECK constraints */
-    char       *partkeydef;        /* partition key definition */
-    char       *partbound;        /* partition bound definition */
     bool        needs_override; /* has GENERATED ALWAYS AS IDENTITY */
     char       *amname;            /* relation access method */

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 294f8fcbbb..8aa34c052d 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -735,10 +735,10 @@ main(int argc, char **argv)


     /*
-     * We allow the server to be back to 8.0, and up to any minor release of
+     * We allow the server to be back to 8.4, and up to any minor release of
      * our own major version.  (See also version check in pg_dumpall.c.)
      */
-    fout->minRemoteVersion = 80000;
+    fout->minRemoteVersion = 80400;
     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;

     fout->numWorkers = numWorkers;
@@ -6812,13 +6812,15 @@ getInherits(Archive *fout, int *numInherits)
 void
 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 {
-    int            i,
-                j;
     PQExpBuffer query = createPQExpBuffer();
+    PQExpBuffer tbloids = createPQExpBuffer();
     PGresult   *res;
+    int            ntups;
+    int            curtblindx;
     IndxInfo   *indxinfo;
     int            i_tableoid,
                 i_oid,
+                i_indrelid,
                 i_indexname,
                 i_parentidx,
                 i_indexdef,
@@ -6838,9 +6840,17 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                 i_indreloptions,
                 i_indstatcols,
                 i_indstatvals;
-    int            ntups;

-    for (i = 0; i < numTables; i++)
+    /*
+     * We want to perform just one query against pg_index.  However, we
+     * mustn't try to select every row of the catalog and then sort it out on
+     * the client side, because some of the server-side functions we need
+     * would be unsafe to apply to tables we don't have lock on.  Hence, we
+     * build an array of the OIDs of tables we care about (and now have lock
+     * on!), and use a WHERE clause to constrain which rows are selected.
+     */
+    appendPQExpBufferChar(tbloids, '{');
+    for (int i = 0; i < numTables; i++)
     {
         TableInfo  *tbinfo = &tblinfo[i];

@@ -6853,232 +6863,270 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
         if (!tbinfo->interesting)
             continue;

-        pg_log_info("reading indexes for table \"%s.%s\"",
-                    tbinfo->dobj.namespace->dobj.name,
-                    tbinfo->dobj.name);
+        /* OK, we need info for this table */
+        if (tbloids->len > 1)    /* do we have more than the '{'? */
+            appendPQExpBufferChar(tbloids, ',');
+        appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
+    }
+    appendPQExpBufferChar(tbloids, '}');

+    /*
+     * The point of the messy-looking outer join is to find a constraint that
+     * is related by an internal dependency link to the index. If we find one,
+     * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
+     * index won't have more than one internal dependency.
+     *
+     * As of 9.0 we don't need to look at pg_depend but can check for a match
+     * to pg_constraint.conindid.  The check on conrelid is redundant but
+     * useful because that column is indexed while conindid is not.
+     */
+    if (fout->remoteVersion >= 110000)
+    {
+        appendPQExpBuffer(query,
+                          "SELECT t.tableoid, t.oid, i.indrelid, "
+                          "t.relname AS indexname, "
+                          "inh.inhparent AS parentidx, "
+                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
+                          "i.indnkeyatts AS indnkeyatts, "
+                          "i.indnatts AS indnatts, "
+                          "i.indkey, i.indisclustered, "
+                          "i.indisreplident, "
+                          "c.contype, c.conname, "
+                          "c.condeferrable, c.condeferred, "
+                          "c.tableoid AS contableoid, "
+                          "c.oid AS conoid, "
+                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
+                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
+                          "t.reloptions AS indreloptions, "
+                          "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
+                          "  FROM pg_catalog.pg_attribute "
+                          "  WHERE attrelid = i.indexrelid AND "
+                          "    attstattarget >= 0) AS indstatcols,"
+                          "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
+                          "  FROM pg_catalog.pg_attribute "
+                          "  WHERE attrelid = i.indexrelid AND "
+                          "    attstattarget >= 0) AS indstatvals "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
+                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
+                          "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
+                          "LEFT JOIN pg_catalog.pg_constraint c "
+                          "ON (i.indrelid = c.conrelid AND "
+                          "i.indexrelid = c.conindid AND "
+                          "c.contype IN ('p','u','x')) "
+                          "LEFT JOIN pg_catalog.pg_inherits inh "
+                          "ON (inh.inhrelid = indexrelid) "
+                          "WHERE (i.indisvalid OR t2.relkind = 'p') "
+                          "AND i.indisready "
+                          "ORDER BY i.indrelid, indexname",
+                          tbloids->data);
+    }
+    else if (fout->remoteVersion >= 90400)
+    {
         /*
-         * The point of the messy-looking outer join is to find a constraint
-         * that is related by an internal dependency link to the index. If we
-         * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
-         * assume an index won't have more than one internal dependency.
-         *
-         * As of 9.0 we don't need to look at pg_depend but can check for a
-         * match to pg_constraint.conindid.  The check on conrelid is
-         * redundant but useful because that column is indexed while conindid
-         * is not.
+         * the test on indisready is necessary in 9.2, and harmless in
+         * earlier/later versions
          */
-        resetPQExpBuffer(query);
-        if (fout->remoteVersion >= 110000)
-        {
-            appendPQExpBuffer(query,
-                              "SELECT t.tableoid, t.oid, "
-                              "t.relname AS indexname, "
-                              "inh.inhparent AS parentidx, "
-                              "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
-                              "i.indnkeyatts AS indnkeyatts, "
-                              "i.indnatts AS indnatts, "
-                              "i.indkey, i.indisclustered, "
-                              "i.indisreplident, "
-                              "c.contype, c.conname, "
-                              "c.condeferrable, c.condeferred, "
-                              "c.tableoid AS contableoid, "
-                              "c.oid AS conoid, "
-                              "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
-                              "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
-                              "t.reloptions AS indreloptions, "
-                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
-                              "  FROM pg_catalog.pg_attribute "
-                              "  WHERE attrelid = i.indexrelid AND "
-                              "    attstattarget >= 0) AS indstatcols,"
-                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
-                              "  FROM pg_catalog.pg_attribute "
-                              "  WHERE attrelid = i.indexrelid AND "
-                              "    attstattarget >= 0) AS indstatvals "
-                              "FROM pg_catalog.pg_index i "
-                              "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
-                              "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
-                              "LEFT JOIN pg_catalog.pg_constraint c "
-                              "ON (i.indrelid = c.conrelid AND "
-                              "i.indexrelid = c.conindid AND "
-                              "c.contype IN ('p','u','x')) "
-                              "LEFT JOIN pg_catalog.pg_inherits inh "
-                              "ON (inh.inhrelid = indexrelid) "
-                              "WHERE i.indrelid = '%u'::pg_catalog.oid "
-                              "AND (i.indisvalid OR t2.relkind = 'p') "
-                              "AND i.indisready "
-                              "ORDER BY indexname",
-                              tbinfo->dobj.catId.oid);
-        }
-        else if (fout->remoteVersion >= 90400)
-        {
-            /*
-             * the test on indisready is necessary in 9.2, and harmless in
-             * earlier/later versions
-             */
-            appendPQExpBuffer(query,
-                              "SELECT t.tableoid, t.oid, "
-                              "t.relname AS indexname, "
-                              "0 AS parentidx, "
-                              "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
-                              "i.indnatts AS indnkeyatts, "
-                              "i.indnatts AS indnatts, "
-                              "i.indkey, i.indisclustered, "
-                              "i.indisreplident, "
-                              "c.contype, c.conname, "
-                              "c.condeferrable, c.condeferred, "
-                              "c.tableoid AS contableoid, "
-                              "c.oid AS conoid, "
-                              "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
-                              "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
-                              "t.reloptions AS indreloptions, "
-                              "'' AS indstatcols, "
-                              "'' AS indstatvals "
-                              "FROM pg_catalog.pg_index i "
-                              "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
-                              "LEFT JOIN pg_catalog.pg_constraint c "
-                              "ON (i.indrelid = c.conrelid AND "
-                              "i.indexrelid = c.conindid AND "
-                              "c.contype IN ('p','u','x')) "
-                              "WHERE i.indrelid = '%u'::pg_catalog.oid "
-                              "AND i.indisvalid AND i.indisready "
-                              "ORDER BY indexname",
-                              tbinfo->dobj.catId.oid);
-        }
-        else if (fout->remoteVersion >= 90000)
-        {
-            /*
-             * the test on indisready is necessary in 9.2, and harmless in
-             * earlier/later versions
-             */
-            appendPQExpBuffer(query,
-                              "SELECT t.tableoid, t.oid, "
-                              "t.relname AS indexname, "
-                              "0 AS parentidx, "
-                              "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
-                              "i.indnatts AS indnkeyatts, "
-                              "i.indnatts AS indnatts, "
-                              "i.indkey, i.indisclustered, "
-                              "false AS indisreplident, "
-                              "c.contype, c.conname, "
-                              "c.condeferrable, c.condeferred, "
-                              "c.tableoid AS contableoid, "
-                              "c.oid AS conoid, "
-                              "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
-                              "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
-                              "t.reloptions AS indreloptions, "
-                              "'' AS indstatcols, "
-                              "'' AS indstatvals "
-                              "FROM pg_catalog.pg_index i "
-                              "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
-                              "LEFT JOIN pg_catalog.pg_constraint c "
-                              "ON (i.indrelid = c.conrelid AND "
-                              "i.indexrelid = c.conindid AND "
-                              "c.contype IN ('p','u','x')) "
-                              "WHERE i.indrelid = '%u'::pg_catalog.oid "
-                              "AND i.indisvalid AND i.indisready "
-                              "ORDER BY indexname",
-                              tbinfo->dobj.catId.oid);
-        }
-        else if (fout->remoteVersion >= 80200)
-        {
-            appendPQExpBuffer(query,
-                              "SELECT t.tableoid, t.oid, "
-                              "t.relname AS indexname, "
-                              "0 AS parentidx, "
-                              "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
-                              "i.indnatts AS indnkeyatts, "
-                              "i.indnatts AS indnatts, "
-                              "i.indkey, i.indisclustered, "
-                              "false AS indisreplident, "
-                              "c.contype, c.conname, "
-                              "c.condeferrable, c.condeferred, "
-                              "c.tableoid AS contableoid, "
-                              "c.oid AS conoid, "
-                              "null AS condef, "
-                              "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
-                              "t.reloptions AS indreloptions, "
-                              "'' AS indstatcols, "
-                              "'' AS indstatvals "
-                              "FROM pg_catalog.pg_index i "
-                              "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
-                              "LEFT JOIN pg_catalog.pg_depend d "
-                              "ON (d.classid = t.tableoid "
-                              "AND d.objid = t.oid "
-                              "AND d.deptype = 'i') "
-                              "LEFT JOIN pg_catalog.pg_constraint c "
-                              "ON (d.refclassid = c.tableoid "
-                              "AND d.refobjid = c.oid) "
-                              "WHERE i.indrelid = '%u'::pg_catalog.oid "
-                              "AND i.indisvalid "
-                              "ORDER BY indexname",
-                              tbinfo->dobj.catId.oid);
-        }
-        else
-        {
-            appendPQExpBuffer(query,
-                              "SELECT t.tableoid, t.oid, "
-                              "t.relname AS indexname, "
-                              "0 AS parentidx, "
-                              "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
-                              "t.relnatts AS indnkeyatts, "
-                              "t.relnatts AS indnatts, "
-                              "i.indkey, i.indisclustered, "
-                              "false AS indisreplident, "
-                              "c.contype, c.conname, "
-                              "c.condeferrable, c.condeferred, "
-                              "c.tableoid AS contableoid, "
-                              "c.oid AS conoid, "
-                              "null AS condef, "
-                              "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
-                              "null AS indreloptions, "
-                              "'' AS indstatcols, "
-                              "'' AS indstatvals "
-                              "FROM pg_catalog.pg_index i "
-                              "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
-                              "LEFT JOIN pg_catalog.pg_depend d "
-                              "ON (d.classid = t.tableoid "
-                              "AND d.objid = t.oid "
-                              "AND d.deptype = 'i') "
-                              "LEFT JOIN pg_catalog.pg_constraint c "
-                              "ON (d.refclassid = c.tableoid "
-                              "AND d.refobjid = c.oid) "
-                              "WHERE i.indrelid = '%u'::pg_catalog.oid "
-                              "ORDER BY indexname",
-                              tbinfo->dobj.catId.oid);
-        }
+        appendPQExpBuffer(query,
+                          "SELECT t.tableoid, t.oid, i.indrelid, "
+                          "t.relname AS indexname, "
+                          "0 AS parentidx, "
+                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
+                          "i.indnatts AS indnkeyatts, "
+                          "i.indnatts AS indnatts, "
+                          "i.indkey, i.indisclustered, "
+                          "i.indisreplident, "
+                          "c.contype, c.conname, "
+                          "c.condeferrable, c.condeferred, "
+                          "c.tableoid AS contableoid, "
+                          "c.oid AS conoid, "
+                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
+                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
+                          "t.reloptions AS indreloptions, "
+                          "'' AS indstatcols, "
+                          "'' AS indstatvals "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
+                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
+                          "LEFT JOIN pg_catalog.pg_constraint c "
+                          "ON (i.indrelid = c.conrelid AND "
+                          "i.indexrelid = c.conindid AND "
+                          "c.contype IN ('p','u','x')) "
+                          "WHERE i.indisvalid AND i.indisready "
+                          "ORDER BY i.indrelid, indexname",
+                          tbloids->data);
+    }
+    else if (fout->remoteVersion >= 90000)
+    {
+        /*
+         * the test on indisready is necessary in 9.2, and harmless in
+         * earlier/later versions
+         */
+        appendPQExpBuffer(query,
+                          "SELECT t.tableoid, t.oid, i.indrelid, "
+                          "t.relname AS indexname, "
+                          "0 AS parentidx, "
+                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
+                          "i.indnatts AS indnkeyatts, "
+                          "i.indnatts AS indnatts, "
+                          "i.indkey, i.indisclustered, "
+                          "false AS indisreplident, "
+                          "c.contype, c.conname, "
+                          "c.condeferrable, c.condeferred, "
+                          "c.tableoid AS contableoid, "
+                          "c.oid AS conoid, "
+                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
+                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
+                          "t.reloptions AS indreloptions, "
+                          "'' AS indstatcols, "
+                          "'' AS indstatvals "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
+                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
+                          "LEFT JOIN pg_catalog.pg_constraint c "
+                          "ON (i.indrelid = c.conrelid AND "
+                          "i.indexrelid = c.conindid AND "
+                          "c.contype IN ('p','u','x')) "
+                          "WHERE i.indisvalid AND i.indisready "
+                          "ORDER BY i.indrelid, indexname",
+                          tbloids->data);
+    }
+    else if (fout->remoteVersion >= 80200)
+    {
+        appendPQExpBuffer(query,
+                          "SELECT t.tableoid, t.oid, i.indrelid, "
+                          "t.relname AS indexname, "
+                          "0 AS parentidx, "
+                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
+                          "i.indnatts AS indnkeyatts, "
+                          "i.indnatts AS indnatts, "
+                          "i.indkey, i.indisclustered, "
+                          "false AS indisreplident, "
+                          "c.contype, c.conname, "
+                          "c.condeferrable, c.condeferred, "
+                          "c.tableoid AS contableoid, "
+                          "c.oid AS conoid, "
+                          "null AS condef, "
+                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
+                          "t.reloptions AS indreloptions, "
+                          "'' AS indstatcols, "
+                          "'' AS indstatvals "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
+                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
+                          "LEFT JOIN pg_catalog.pg_depend d "
+                          "ON (d.classid = t.tableoid "
+                          "AND d.objid = t.oid "
+                          "AND d.deptype = 'i') "
+                          "LEFT JOIN pg_catalog.pg_constraint c "
+                          "ON (d.refclassid = c.tableoid "
+                          "AND d.refobjid = c.oid) "
+                          "WHERE i.indisvalid "
+                          "ORDER BY i.indrelid, indexname",
+                          tbloids->data);
+    }
+    else
+    {
+        appendPQExpBuffer(query,
+                          "SELECT t.tableoid, t.oid, i.indrelid, "
+                          "t.relname AS indexname, "
+                          "0 AS parentidx, "
+                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
+                          "t.relnatts AS indnkeyatts, "
+                          "t.relnatts AS indnatts, "
+                          "i.indkey, i.indisclustered, "
+                          "false AS indisreplident, "
+                          "c.contype, c.conname, "
+                          "c.condeferrable, c.condeferred, "
+                          "c.tableoid AS contableoid, "
+                          "c.oid AS conoid, "
+                          "null AS condef, "
+                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS
tablespace," 
+                          "null AS indreloptions, "
+                          "'' AS indstatcols, "
+                          "'' AS indstatvals "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
+                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
+                          "LEFT JOIN pg_catalog.pg_depend d "
+                          "ON (d.classid = t.tableoid "
+                          "AND d.objid = t.oid "
+                          "AND d.deptype = 'i') "
+                          "LEFT JOIN pg_catalog.pg_constraint c "
+                          "ON (d.refclassid = c.tableoid "
+                          "AND d.refobjid = c.oid) "
+                          "ORDER BY i.indrelid, indexname",
+                          tbloids->data);
+    }

-        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+    res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

-        ntups = PQntuples(res);
+    ntups = PQntuples(res);

-        i_tableoid = PQfnumber(res, "tableoid");
-        i_oid = PQfnumber(res, "oid");
-        i_indexname = PQfnumber(res, "indexname");
-        i_parentidx = PQfnumber(res, "parentidx");
-        i_indexdef = PQfnumber(res, "indexdef");
-        i_indnkeyatts = PQfnumber(res, "indnkeyatts");
-        i_indnatts = PQfnumber(res, "indnatts");
-        i_indkey = PQfnumber(res, "indkey");
-        i_indisclustered = PQfnumber(res, "indisclustered");
-        i_indisreplident = PQfnumber(res, "indisreplident");
-        i_contype = PQfnumber(res, "contype");
-        i_conname = PQfnumber(res, "conname");
-        i_condeferrable = PQfnumber(res, "condeferrable");
-        i_condeferred = PQfnumber(res, "condeferred");
-        i_contableoid = PQfnumber(res, "contableoid");
-        i_conoid = PQfnumber(res, "conoid");
-        i_condef = PQfnumber(res, "condef");
-        i_tablespace = PQfnumber(res, "tablespace");
-        i_indreloptions = PQfnumber(res, "indreloptions");
-        i_indstatcols = PQfnumber(res, "indstatcols");
-        i_indstatvals = PQfnumber(res, "indstatvals");
-
-        tbinfo->indexes = indxinfo =
-            (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
-        tbinfo->numIndexes = ntups;
+    i_tableoid = PQfnumber(res, "tableoid");
+    i_oid = PQfnumber(res, "oid");
+    i_indrelid = PQfnumber(res, "indrelid");
+    i_indexname = PQfnumber(res, "indexname");
+    i_parentidx = PQfnumber(res, "parentidx");
+    i_indexdef = PQfnumber(res, "indexdef");
+    i_indnkeyatts = PQfnumber(res, "indnkeyatts");
+    i_indnatts = PQfnumber(res, "indnatts");
+    i_indkey = PQfnumber(res, "indkey");
+    i_indisclustered = PQfnumber(res, "indisclustered");
+    i_indisreplident = PQfnumber(res, "indisreplident");
+    i_contype = PQfnumber(res, "contype");
+    i_conname = PQfnumber(res, "conname");
+    i_condeferrable = PQfnumber(res, "condeferrable");
+    i_condeferred = PQfnumber(res, "condeferred");
+    i_contableoid = PQfnumber(res, "contableoid");
+    i_conoid = PQfnumber(res, "conoid");
+    i_condef = PQfnumber(res, "condef");
+    i_tablespace = PQfnumber(res, "tablespace");
+    i_indreloptions = PQfnumber(res, "indreloptions");
+    i_indstatcols = PQfnumber(res, "indstatcols");
+    i_indstatvals = PQfnumber(res, "indstatvals");

-        for (j = 0; j < ntups; j++)
+    indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
+
+    /*
+     * Outer loop iterates once per table, not once per row.  Incrementing of
+     * j is handled by the inner loop.
+     */
+    curtblindx = -1;
+    for (int j = 0; j < ntups;)
+    {
+        Oid            indrelid = atooid(PQgetvalue(res, j, i_indrelid));
+        TableInfo  *tbinfo = NULL;
+        int            numinds;
+
+        /* Count rows for this table */
+        for (numinds = 1; numinds < ntups - j; numinds++)
+            if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
+                break;
+
+        /*
+         * Locate the associated TableInfo; we rely on tblinfo[] being in OID
+         * order.
+         */
+        while (++curtblindx < numTables)
+        {
+            tbinfo = &tblinfo[curtblindx];
+            if (tbinfo->dobj.catId.oid == indrelid)
+                break;
+        }
+        if (curtblindx >= numTables)
+            fatal("unrecognized table OID %u", indrelid);
+        /* cross-check that we only got requested tables */
+        if (!tbinfo->hasindex ||
+            !tbinfo->interesting)
+            fatal("unexpected index data for table \"%s\"",
+                  tbinfo->dobj.name);
+
+        /* Save data for this table */
+        tbinfo->indexes = indxinfo + j;
+        tbinfo->numIndexes = numinds;
+
+        for (int c = 0; c < numinds; c++, j++)
         {
             char        contype;

@@ -7147,11 +7195,12 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                 indxinfo[j].indexconstraint = 0;
             }
         }
-
-        PQclear(res);
     }

+    PQclear(res);
+
     destroyPQExpBuffer(query);
+    destroyPQExpBuffer(tbloids);
 }

 /*
@@ -7238,22 +7287,31 @@ getExtendedStatistics(Archive *fout)
 void
 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
 {
-    int            i,
-                j;
-    ConstraintInfo *constrinfo;
-    PQExpBuffer query;
+    PQExpBuffer query = createPQExpBuffer();
+    PQExpBuffer tbloids = createPQExpBuffer();
     PGresult   *res;
+    int            ntups;
+    int            curtblindx;
+    TableInfo  *tbinfo = NULL;
+    ConstraintInfo *constrinfo;
     int            i_contableoid,
                 i_conoid,
+                i_conrelid,
                 i_conname,
                 i_confrelid,
                 i_conindid,
                 i_condef;
-    int            ntups;

-    query = createPQExpBuffer();
-
-    for (i = 0; i < numTables; i++)
+    /*
+     * We want to perform just one query against pg_constraint.  However, we
+     * mustn't try to select every row of the catalog and then sort it out on
+     * the client side, because some of the server-side functions we need
+     * would be unsafe to apply to tables we don't have lock on.  Hence, we
+     * build an array of the OIDs of tables we care about (and now have lock
+     * on!), and use a WHERE clause to constrain which rows are selected.
+     */
+    appendPQExpBufferChar(tbloids, '{');
+    for (int i = 0; i < numTables; i++)
     {
         TableInfo  *tbinfo = &tblinfo[i];

@@ -7266,95 +7324,118 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
             continue;

-        pg_log_info("reading foreign key constraints for table \"%s.%s\"",
-                    tbinfo->dobj.namespace->dobj.name,
-                    tbinfo->dobj.name);
+        /* OK, we need info for this table */
+        if (tbloids->len > 1)    /* do we have more than the '{'? */
+            appendPQExpBufferChar(tbloids, ',');
+        appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
+    }
+    appendPQExpBufferChar(tbloids, '}');

-        resetPQExpBuffer(query);
-        if (fout->remoteVersion >= 110000)
-            appendPQExpBuffer(query,
-                              "SELECT tableoid, oid, conname, confrelid, conindid, "
-                              "pg_catalog.pg_get_constraintdef(oid) AS condef "
-                              "FROM pg_catalog.pg_constraint "
-                              "WHERE conrelid = '%u'::pg_catalog.oid "
-                              "AND conparentid = 0 "
-                              "AND contype = 'f'",
-                              tbinfo->dobj.catId.oid);
-        else
-            appendPQExpBuffer(query,
-                              "SELECT tableoid, oid, conname, confrelid, 0 as conindid, "
-                              "pg_catalog.pg_get_constraintdef(oid) AS condef "
-                              "FROM pg_catalog.pg_constraint "
-                              "WHERE conrelid = '%u'::pg_catalog.oid "
-                              "AND contype = 'f'",
-                              tbinfo->dobj.catId.oid);
-        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+    appendPQExpBufferStr(query,
+                         "SELECT c.tableoid, c.oid, "
+                         "conrelid, conname, confrelid, ");
+    if (fout->remoteVersion >= 110000)
+        appendPQExpBufferStr(query, "conindid, ");
+    else
+        appendPQExpBufferStr(query, "0 AS conindid, ");
+    appendPQExpBuffer(query,
+                      "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
+                      "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                      "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
+                      "WHERE contype = 'f' ",
+                      tbloids->data);
+    if (fout->remoteVersion >= 110000)
+        appendPQExpBufferStr(query,
+                             "AND conparentid = 0 ");
+    appendPQExpBufferStr(query,
+                         "ORDER BY conrelid, conname");

-        ntups = PQntuples(res);
+    res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

-        i_contableoid = PQfnumber(res, "tableoid");
-        i_conoid = PQfnumber(res, "oid");
-        i_conname = PQfnumber(res, "conname");
-        i_confrelid = PQfnumber(res, "confrelid");
-        i_conindid = PQfnumber(res, "conindid");
-        i_condef = PQfnumber(res, "condef");
+    ntups = PQntuples(res);

-        constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
+    i_contableoid = PQfnumber(res, "tableoid");
+    i_conoid = PQfnumber(res, "oid");
+    i_conrelid = PQfnumber(res, "conrelid");
+    i_conname = PQfnumber(res, "conname");
+    i_confrelid = PQfnumber(res, "confrelid");
+    i_conindid = PQfnumber(res, "conindid");
+    i_condef = PQfnumber(res, "condef");

-        for (j = 0; j < ntups; j++)
-        {
-            TableInfo  *reftable;
-
-            constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
-            constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
-            constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
-            AssignDumpId(&constrinfo[j].dobj);
-            constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
-            constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
-            constrinfo[j].contable = tbinfo;
-            constrinfo[j].condomain = NULL;
-            constrinfo[j].contype = 'f';
-            constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
-            constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
-            constrinfo[j].conindex = 0;
-            constrinfo[j].condeferrable = false;
-            constrinfo[j].condeferred = false;
-            constrinfo[j].conislocal = true;
-            constrinfo[j].separate = true;
+    constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));

-            /*
-             * Restoring an FK that points to a partitioned table requires
-             * that all partition indexes have been attached beforehand.
-             * Ensure that happens by making the constraint depend on each
-             * index partition attach object.
-             */
-            reftable = findTableByOid(constrinfo[j].confrelid);
-            if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
+    curtblindx = -1;
+    for (int j = 0; j < ntups; j++)
+    {
+        Oid            conrelid = atooid(PQgetvalue(res, j, i_conrelid));
+        TableInfo  *reftable;
+
+        /*
+         * Locate the associated TableInfo; we rely on tblinfo[] being in OID
+         * order.
+         */
+        if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
+        {
+            while (++curtblindx < numTables)
             {
-                Oid            indexOid = atooid(PQgetvalue(res, j, i_conindid));
+                tbinfo = &tblinfo[curtblindx];
+                if (tbinfo->dobj.catId.oid == conrelid)
+                    break;
+            }
+            if (curtblindx >= numTables)
+                fatal("unrecognized table OID %u", conrelid);
+        }
+
+        constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
+        constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
+        constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
+        AssignDumpId(&constrinfo[j].dobj);
+        constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
+        constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
+        constrinfo[j].contable = tbinfo;
+        constrinfo[j].condomain = NULL;
+        constrinfo[j].contype = 'f';
+        constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
+        constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
+        constrinfo[j].conindex = 0;
+        constrinfo[j].condeferrable = false;
+        constrinfo[j].condeferred = false;
+        constrinfo[j].conislocal = true;
+        constrinfo[j].separate = true;
+
+        /*
+         * Restoring an FK that points to a partitioned table requires that
+         * all partition indexes have been attached beforehand. Ensure that
+         * happens by making the constraint depend on each index partition
+         * attach object.
+         */
+        reftable = findTableByOid(constrinfo[j].confrelid);
+        if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
+        {
+            Oid            indexOid = atooid(PQgetvalue(res, j, i_conindid));

-                if (indexOid != InvalidOid)
+            if (indexOid != InvalidOid)
+            {
+                for (int k = 0; k < reftable->numIndexes; k++)
                 {
-                    for (int k = 0; k < reftable->numIndexes; k++)
-                    {
-                        IndxInfo   *refidx;
+                    IndxInfo   *refidx;

-                        /* not our index? */
-                        if (reftable->indexes[k].dobj.catId.oid != indexOid)
-                            continue;
+                    /* not our index? */
+                    if (reftable->indexes[k].dobj.catId.oid != indexOid)
+                        continue;

-                        refidx = &reftable->indexes[k];
-                        addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
-                        break;
-                    }
+                    refidx = &reftable->indexes[k];
+                    addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
+                    break;
                 }
             }
         }
-
-        PQclear(res);
     }

+    PQclear(res);
+
     destroyPQExpBuffer(query);
+    destroyPQExpBuffer(tbloids);
 }

 /*
@@ -7598,13 +7679,15 @@ getRules(Archive *fout, int *numRules)
 void
 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 {
-    int            i,
-                j;
     PQExpBuffer query = createPQExpBuffer();
+    PQExpBuffer tbloids = createPQExpBuffer();
     PGresult   *res;
+    int            ntups;
+    int            curtblindx;
     TriggerInfo *tginfo;
     int            i_tableoid,
                 i_oid,
+                i_tgrelid,
                 i_tgname,
                 i_tgfname,
                 i_tgtype,
@@ -7619,9 +7702,17 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
                 i_tgdeferrable,
                 i_tginitdeferred,
                 i_tgdef;
-    int            ntups;

-    for (i = 0; i < numTables; i++)
+    /*
+     * We want to perform just one query against pg_trigger.  However, we
+     * mustn't try to select every row of the catalog and then sort it out on
+     * the client side, because some of the server-side functions we need
+     * would be unsafe to apply to tables we don't have lock on.  Hence, we
+     * build an array of the OIDs of tables we care about (and now have lock
+     * on!), and use a WHERE clause to constrain which rows are selected.
+     */
+    appendPQExpBufferChar(tbloids, '{');
+    for (int i = 0; i < numTables; i++)
     {
         TableInfo  *tbinfo = &tblinfo[i];

@@ -7629,143 +7720,178 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
             continue;

-        pg_log_info("reading triggers for table \"%s.%s\"",
-                    tbinfo->dobj.namespace->dobj.name,
-                    tbinfo->dobj.name);
+        /* OK, we need info for this table */
+        if (tbloids->len > 1)    /* do we have more than the '{'? */
+            appendPQExpBufferChar(tbloids, ',');
+        appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
+    }
+    appendPQExpBufferChar(tbloids, '}');

-        resetPQExpBuffer(query);
-        if (fout->remoteVersion >= 130000)
-        {
-            /*
-             * NB: think not to use pretty=true in pg_get_triggerdef.  It
-             * could result in non-forward-compatible dumps of WHEN clauses
-             * due to under-parenthesization.
-             *
-             * NB: We need to see tgisinternal triggers in partitions, in case
-             * the tgenabled flag has been changed from the parent.
-             */
-            appendPQExpBuffer(query,
-                              "SELECT t.tgname, "
-                              "t.tgfoid::pg_catalog.regproc AS tgfname, "
-                              "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
-                              "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
-                              "FROM pg_catalog.pg_trigger t "
-                              "LEFT JOIN pg_catalog.pg_trigger u ON u.oid = t.tgparentid "
-                              "WHERE t.tgrelid = '%u'::pg_catalog.oid "
-                              "AND (NOT t.tgisinternal OR t.tgenabled != u.tgenabled)",
-                              tbinfo->dobj.catId.oid);
-        }
-        else if (fout->remoteVersion >= 110000)
-        {
-            /*
-             * NB: We need to see tgisinternal triggers in partitions, in case
-             * the tgenabled flag has been changed from the parent. No
-             * tgparentid in version 11-12, so we have to match them via
-             * pg_depend.
-             *
-             * See above about pretty=true in pg_get_triggerdef.
-             */
-            appendPQExpBuffer(query,
-                              "SELECT t.tgname, "
-                              "t.tgfoid::pg_catalog.regproc AS tgfname, "
-                              "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
-                              "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
-                              "FROM pg_catalog.pg_trigger t "
-                              "LEFT JOIN pg_catalog.pg_depend AS d ON "
-                              " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
-                              " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
-                              " d.objid = t.oid "
-                              "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
-                              "WHERE t.tgrelid = '%u'::pg_catalog.oid "
-                              "AND (NOT t.tgisinternal%s)",
-                              tbinfo->dobj.catId.oid,
-                              tbinfo->ispartition ?
-                              " OR t.tgenabled != pt.tgenabled" : "");
-        }
-        else if (fout->remoteVersion >= 90000)
-        {
-            /* See above about pretty=true in pg_get_triggerdef */
-            appendPQExpBuffer(query,
-                              "SELECT t.tgname, "
-                              "t.tgfoid::pg_catalog.regproc AS tgfname, "
-                              "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
-                              "t.tgenabled, false as tgisinternal, "
-                              "t.tableoid, t.oid "
-                              "FROM pg_catalog.pg_trigger t "
-                              "WHERE tgrelid = '%u'::pg_catalog.oid "
-                              "AND NOT tgisinternal",
-                              tbinfo->dobj.catId.oid);
-        }
-        else if (fout->remoteVersion >= 80300)
-        {
-            /*
-             * We ignore triggers that are tied to a foreign-key constraint
-             */
-            appendPQExpBuffer(query,
-                              "SELECT tgname, "
-                              "tgfoid::pg_catalog.regproc AS tgfname, "
-                              "tgtype, tgnargs, tgargs, tgenabled, "
-                              "false as tgisinternal, "
-                              "tgisconstraint, tgconstrname, tgdeferrable, "
-                              "tgconstrrelid, tginitdeferred, tableoid, oid, "
-                              "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
-                              "FROM pg_catalog.pg_trigger t "
-                              "WHERE tgrelid = '%u'::pg_catalog.oid "
-                              "AND tgconstraint = 0",
-                              tbinfo->dobj.catId.oid);
-        }
-        else
-        {
-            /*
-             * We ignore triggers that are tied to a foreign-key constraint,
-             * but in these versions we have to grovel through pg_constraint
-             * to find out
-             */
-            appendPQExpBuffer(query,
-                              "SELECT tgname, "
-                              "tgfoid::pg_catalog.regproc AS tgfname, "
-                              "tgtype, tgnargs, tgargs, tgenabled, "
-                              "false as tgisinternal, "
-                              "tgisconstraint, tgconstrname, tgdeferrable, "
-                              "tgconstrrelid, tginitdeferred, tableoid, oid, "
-                              "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
-                              "FROM pg_catalog.pg_trigger t "
-                              "WHERE tgrelid = '%u'::pg_catalog.oid "
-                              "AND (NOT tgisconstraint "
-                              " OR NOT EXISTS"
-                              "  (SELECT 1 FROM pg_catalog.pg_depend d "
-                              "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid =
c.oid)" 
-                              "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype =
'f'))",
-                              tbinfo->dobj.catId.oid);
-        }
+    if (fout->remoteVersion >= 130000)
+    {
+        /*
+         * NB: think not to use pretty=true in pg_get_triggerdef.  It could
+         * result in non-forward-compatible dumps of WHEN clauses due to
+         * under-parenthesization.
+         *
+         * NB: We need to see tgisinternal triggers in partitions, in case the
+         * tgenabled flag has been changed from the parent.
+         */
+        appendPQExpBuffer(query,
+                          "SELECT t.tgrelid, t.tgname, "
+                          "t.tgfoid::pg_catalog.regproc AS tgfname, "
+                          "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
+                          "t.tgenabled, t.tableoid, t.oid, t.tgisinternal\n"
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
+                          "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
+                          "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
+                          "ORDER BY t.tgrelid, t.tgname",
+                          tbloids->data);
+    }
+    else if (fout->remoteVersion >= 110000)
+    {
+        /*
+         * NB: We need to see tgisinternal triggers in partitions, in case the
+         * tgenabled flag has been changed from the parent. No tgparentid in
+         * version 11-12, so we have to match them via pg_depend.
+         *
+         * See above about pretty=true in pg_get_triggerdef.
+         */
+        appendPQExpBuffer(query,
+                          "SELECT t.tgrelid, t.tgname, "
+                          "t.tgfoid::pg_catalog.regproc AS tgfname, "
+                          "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
+                          "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
+                          "LEFT JOIN pg_catalog.pg_depend AS d ON "
+                          " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
+                          " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
+                          " d.objid = t.oid "
+                          "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
+                          "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
+                          "ORDER BY t.tgrelid, t.tgname",
+                          tbloids->data);
+    }
+    else if (fout->remoteVersion >= 90000)
+    {
+        /* See above about pretty=true in pg_get_triggerdef */
+        appendPQExpBuffer(query,
+                          "SELECT t.tgrelid, t.tgname, "
+                          "t.tgfoid::pg_catalog.regproc AS tgfname, "
+                          "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
+                          "t.tgenabled, false as tgisinternal, "
+                          "t.tableoid, t.oid "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
+                          "WHERE NOT tgisinternal "
+                          "ORDER BY t.tgrelid, t.tgname",
+                          tbloids->data);
+    }
+    else if (fout->remoteVersion >= 80300)
+    {
+        /*
+         * We ignore triggers that are tied to a foreign-key constraint
+         */
+        appendPQExpBuffer(query,
+                          "SELECT t.tgrelid, tgname, "
+                          "tgfoid::pg_catalog.regproc AS tgfname, "
+                          "tgtype, tgnargs, tgargs, tgenabled, "
+                          "false as tgisinternal, "
+                          "tgisconstraint, tgconstrname, tgdeferrable, "
+                          "tgconstrrelid, tginitdeferred, t.tableoid, t.oid, "
+                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
+                          "WHERE tgconstraint = 0 "
+                          "ORDER BY t.tgrelid, t.tgname",
+                          tbloids->data);
+    }
+    else
+    {
+        /*
+         * We ignore triggers that are tied to a foreign-key constraint, but
+         * in these versions we have to grovel through pg_constraint to find
+         * out
+         */
+        appendPQExpBuffer(query,
+                          "SELECT t.tgrelid, tgname, "
+                          "tgfoid::pg_catalog.regproc AS tgfname, "
+                          "tgtype, tgnargs, tgargs, tgenabled, "
+                          "false as tgisinternal, "
+                          "tgisconstraint, tgconstrname, tgdeferrable, "
+                          "tgconstrrelid, tginitdeferred, t.tableoid, t.oid, "
+                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
+                          "WHERE (NOT tgisconstraint "
+                          " OR NOT EXISTS"
+                          "  (SELECT 1 FROM pg_catalog.pg_depend d "
+                          "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
+                          "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype =
'f'))" 
+                          "ORDER BY t.tgrelid, t.tgname",
+                          tbloids->data);
+    }

-        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+    res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

-        ntups = PQntuples(res);
+    ntups = PQntuples(res);

-        i_tableoid = PQfnumber(res, "tableoid");
-        i_oid = PQfnumber(res, "oid");
-        i_tgname = PQfnumber(res, "tgname");
-        i_tgfname = PQfnumber(res, "tgfname");
-        i_tgtype = PQfnumber(res, "tgtype");
-        i_tgnargs = PQfnumber(res, "tgnargs");
-        i_tgargs = PQfnumber(res, "tgargs");
-        i_tgisconstraint = PQfnumber(res, "tgisconstraint");
-        i_tgconstrname = PQfnumber(res, "tgconstrname");
-        i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
-        i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
-        i_tgenabled = PQfnumber(res, "tgenabled");
-        i_tgisinternal = PQfnumber(res, "tgisinternal");
-        i_tgdeferrable = PQfnumber(res, "tgdeferrable");
-        i_tginitdeferred = PQfnumber(res, "tginitdeferred");
-        i_tgdef = PQfnumber(res, "tgdef");
-
-        tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
-
-        tbinfo->numTriggers = ntups;
-        tbinfo->triggers = tginfo;
+    i_tableoid = PQfnumber(res, "tableoid");
+    i_oid = PQfnumber(res, "oid");
+    i_tgrelid = PQfnumber(res, "tgrelid");
+    i_tgname = PQfnumber(res, "tgname");
+    i_tgfname = PQfnumber(res, "tgfname");
+    i_tgtype = PQfnumber(res, "tgtype");
+    i_tgnargs = PQfnumber(res, "tgnargs");
+    i_tgargs = PQfnumber(res, "tgargs");
+    i_tgisconstraint = PQfnumber(res, "tgisconstraint");
+    i_tgconstrname = PQfnumber(res, "tgconstrname");
+    i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
+    i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
+    i_tgenabled = PQfnumber(res, "tgenabled");
+    i_tgisinternal = PQfnumber(res, "tgisinternal");
+    i_tgdeferrable = PQfnumber(res, "tgdeferrable");
+    i_tginitdeferred = PQfnumber(res, "tginitdeferred");
+    i_tgdef = PQfnumber(res, "tgdef");
+
+    tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));

-        for (j = 0; j < ntups; j++)
+    /*
+     * Outer loop iterates once per table, not once per row.  Incrementing of
+     * j is handled by the inner loop.
+     */
+    curtblindx = -1;
+    for (int j = 0; j < ntups;)
+    {
+        Oid            tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
+        TableInfo  *tbinfo = NULL;
+        int            numtrigs;
+
+        /* Count rows for this table */
+        for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
+            if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
+                break;
+
+        /*
+         * Locate the associated TableInfo; we rely on tblinfo[] being in OID
+         * order.
+         */
+        while (++curtblindx < numTables)
+        {
+            tbinfo = &tblinfo[curtblindx];
+            if (tbinfo->dobj.catId.oid == tgrelid)
+                break;
+        }
+        if (curtblindx >= numTables)
+            fatal("unrecognized table OID %u", tgrelid);
+
+        /* Save data for this table */
+        tbinfo->triggers = tginfo + j;
+        tbinfo->numTriggers = numtrigs;
+
+        for (int c = 0; c < numtrigs; c++, j++)
         {
             tginfo[j].dobj.objType = DO_TRIGGER;
             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
@@ -7828,11 +7954,12 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
                 }
             }
         }
-
-        PQclear(res);
     }

+    PQclear(res);
+
     destroyPQExpBuffer(query);
+    destroyPQExpBuffer(tbloids);
 }

 /*
@@ -8286,12 +8413,6 @@ getTransforms(Archive *fout, int *numTransforms)
  *      for each interesting table, read info about its attributes
  *      (names, types, default values, CHECK constraints, etc)
  *
- * This is implemented in a very inefficient way right now, looping
- * through the tblinfo and doing a join per table to find the attrs and their
- * types.  However, because we want type names and so forth to be named
- * relative to the schema of each table, we couldn't do it in just one
- * query.  (Maybe one query per schema?)
- *
  *    modifies tblinfo
  */
 void
@@ -8299,6 +8420,12 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 {
     DumpOptions *dopt = fout->dopt;
     PQExpBuffer q = createPQExpBuffer();
+    PQExpBuffer tbloids = createPQExpBuffer();
+    PQExpBuffer checkoids = createPQExpBuffer();
+    PGresult   *res;
+    int            ntups;
+    int            curtblindx;
+    int            i_attrelid;
     int            i_attnum;
     int            i_attname;
     int            i_atttypname;
@@ -8320,12 +8447,21 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
     int            i_attmissingval;
     int            i_atthasdef;

+    /*
+     * We want to perform just one query against pg_attribute, and then just
+     * one against pg_attrdef (for DEFAULTs) and one against pg_constraint
+     * (for CHECK constraints).  However, we mustn't try to select every row
+     * of those catalogs and then sort it out on the client side, because some
+     * of the server-side functions we need would be unsafe to apply to tables
+     * we don't have lock on.  Hence, we build an array of the OIDs of tables
+     * we care about (and now have lock on!), and use a WHERE clause to
+     * constrain which rows are selected.
+     */
+    appendPQExpBufferChar(tbloids, '{');
+    appendPQExpBufferChar(checkoids, '{');
     for (int i = 0; i < numTables; i++)
     {
         TableInfo  *tbinfo = &tblinfo[i];
-        PGresult   *res;
-        int            ntups;
-        bool        hasdefaults;

         /* Don't bother to collect info for sequences */
         if (tbinfo->relkind == RELKIND_SEQUENCE)
@@ -8335,390 +8471,499 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
         if (!tbinfo->interesting)
             continue;

-        /* find all the user attributes and their types */
+        /* OK, we need info for this table */
+        if (tbloids->len > 1)    /* do we have more than the '{'? */
+            appendPQExpBufferChar(tbloids, ',');
+        appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
+
+        if (tbinfo->ncheck > 0)
+        {
+            /* Also make a list of the ones with check constraints */
+            if (checkoids->len > 1) /* do we have more than the '{'? */
+                appendPQExpBufferChar(checkoids, ',');
+            appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
+        }
+    }
+    appendPQExpBufferChar(tbloids, '}');
+    appendPQExpBufferChar(checkoids, '}');
+
+    /* find all the user attributes and their types */
+    appendPQExpBufferStr(q,
+                         "SELECT\n"
+                         "a.attrelid,\n"
+                         "a.attnum,\n"
+                         "a.attname,\n"
+                         "a.atttypmod,\n"
+                         "a.attstattarget,\n"
+                         "a.attstorage,\n"
+                         "t.typstorage,\n"
+                         "a.attnotnull,\n"
+                         "a.atthasdef,\n"
+                         "a.attisdropped,\n"
+                         "a.attlen,\n"
+                         "a.attalign,\n"
+                         "a.attislocal,\n"
+                         "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");

+    if (fout->remoteVersion >= 90000)
+        appendPQExpBufferStr(q,
+                             "array_to_string(a.attoptions, ', ') AS attoptions,\n");
+    else
+        appendPQExpBufferStr(q,
+                             "'' AS attoptions,\n");
+
+    if (fout->remoteVersion >= 90100)
+    {
         /*
-         * we must read the attribute names in attribute number order! because
-         * we will use the attnum to index into the attnames array later.
+         * Since we only want to dump COLLATE clauses for attributes whose
+         * collation is different from their type's default, we use a CASE
+         * here to suppress uninteresting attcollations cheaply.
          */
-        pg_log_info("finding the columns and types of table \"%s.%s\"",
-                    tbinfo->dobj.namespace->dobj.name,
-                    tbinfo->dobj.name);
+        appendPQExpBufferStr(q,
+                             "CASE WHEN a.attcollation <> t.typcollation "
+                             "THEN a.attcollation ELSE 0 END AS attcollation,\n");
+    }
+    else
+        appendPQExpBufferStr(q,
+                             "0 AS attcollation,\n");

-        resetPQExpBuffer(q);
+    if (fout->remoteVersion >= 140000)
+        appendPQExpBufferStr(q,
+                             "a.attcompression AS attcompression,\n");
+    else
+        appendPQExpBufferStr(q,
+                             "'' AS attcompression,\n");

+    if (fout->remoteVersion >= 90200)
         appendPQExpBufferStr(q,
-                             "SELECT\n"
-                             "a.attnum,\n"
-                             "a.attname,\n"
-                             "a.atttypmod,\n"
-                             "a.attstattarget,\n"
-                             "a.attstorage,\n"
-                             "t.typstorage,\n"
-                             "a.attnotnull,\n"
-                             "a.atthasdef,\n"
-                             "a.attisdropped,\n"
-                             "a.attlen,\n"
-                             "a.attalign,\n"
-                             "a.attislocal,\n"
-                             "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
-
-        if (fout->remoteVersion >= 90000)
-            appendPQExpBufferStr(q,
-                                 "array_to_string(a.attoptions, ', ') AS attoptions,\n");
-        else
-            appendPQExpBufferStr(q,
-                                 "'' AS attoptions,\n");
+                             "pg_catalog.array_to_string(ARRAY("
+                             "SELECT pg_catalog.quote_ident(option_name) || "
+                             "' ' || pg_catalog.quote_literal(option_value) "
+                             "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
+                             "ORDER BY option_name"
+                             "), E',\n    ') AS attfdwoptions,\n");
+    else
+        appendPQExpBufferStr(q,
+                             "'' AS attfdwoptions,\n");

-        if (fout->remoteVersion >= 90100)
-        {
-            /*
-             * Since we only want to dump COLLATE clauses for attributes whose
-             * collation is different from their type's default, we use a CASE
-             * here to suppress uninteresting attcollations cheaply.
-             */
-            appendPQExpBufferStr(q,
-                                 "CASE WHEN a.attcollation <> t.typcollation "
-                                 "THEN a.attcollation ELSE 0 END AS attcollation,\n");
-        }
-        else
-            appendPQExpBufferStr(q,
-                                 "0 AS attcollation,\n");
+    if (fout->remoteVersion >= 100000)
+        appendPQExpBufferStr(q,
+                             "a.attidentity,\n");
+    else
+        appendPQExpBufferStr(q,
+                             "'' AS attidentity,\n");

-        if (fout->remoteVersion >= 140000)
-            appendPQExpBuffer(q,
-                              "a.attcompression AS attcompression,\n");
-        else
-            appendPQExpBuffer(q,
-                              "'' AS attcompression,\n");
+    if (fout->remoteVersion >= 110000)
+        appendPQExpBufferStr(q,
+                             "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
+                             "THEN a.attmissingval ELSE null END AS attmissingval,\n");
+    else
+        appendPQExpBufferStr(q,
+                             "NULL AS attmissingval,\n");

-        if (fout->remoteVersion >= 90200)
-            appendPQExpBufferStr(q,
-                                 "pg_catalog.array_to_string(ARRAY("
-                                 "SELECT pg_catalog.quote_ident(option_name) || "
-                                 "' ' || pg_catalog.quote_literal(option_value) "
-                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
-                                 "ORDER BY option_name"
-                                 "), E',\n    ') AS attfdwoptions,\n");
-        else
-            appendPQExpBufferStr(q,
-                                 "'' AS attfdwoptions,\n");
+    if (fout->remoteVersion >= 120000)
+        appendPQExpBufferStr(q,
+                             "a.attgenerated\n");
+    else
+        appendPQExpBufferStr(q,
+                             "'' AS attgenerated\n");

-        if (fout->remoteVersion >= 100000)
-            appendPQExpBufferStr(q,
-                                 "a.attidentity,\n");
-        else
-            appendPQExpBufferStr(q,
-                                 "'' AS attidentity,\n");
+    /* need left join to pg_type to not fail on dropped columns ... */
+    appendPQExpBuffer(q,
+                      "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                      "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
+                      "LEFT JOIN pg_catalog.pg_type t "
+                      "ON (a.atttypid = t.oid)\n"
+                      "WHERE a.attnum > 0::pg_catalog.int2\n"
+                      "ORDER BY a.attrelid, a.attnum",
+                      tbloids->data);

-        if (fout->remoteVersion >= 110000)
-            appendPQExpBufferStr(q,
-                                 "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
-                                 "THEN a.attmissingval ELSE null END AS attmissingval,\n");
-        else
-            appendPQExpBufferStr(q,
-                                 "NULL AS attmissingval,\n");
+    res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);

-        if (fout->remoteVersion >= 120000)
-            appendPQExpBufferStr(q,
-                                 "a.attgenerated\n");
-        else
-            appendPQExpBufferStr(q,
-                                 "'' AS attgenerated\n");
+    ntups = PQntuples(res);

-        /* need left join here to not fail on dropped columns ... */
-        appendPQExpBuffer(q,
-                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
-                          "ON a.atttypid = t.oid\n"
-                          "WHERE a.attrelid = '%u'::pg_catalog.oid "
-                          "AND a.attnum > 0::pg_catalog.int2\n"
-                          "ORDER BY a.attnum",
-                          tbinfo->dobj.catId.oid);
+    i_attrelid = PQfnumber(res, "attrelid");
+    i_attnum = PQfnumber(res, "attnum");
+    i_attname = PQfnumber(res, "attname");
+    i_atttypname = PQfnumber(res, "atttypname");
+    i_atttypmod = PQfnumber(res, "atttypmod");
+    i_attstattarget = PQfnumber(res, "attstattarget");
+    i_attstorage = PQfnumber(res, "attstorage");
+    i_typstorage = PQfnumber(res, "typstorage");
+    i_attidentity = PQfnumber(res, "attidentity");
+    i_attgenerated = PQfnumber(res, "attgenerated");
+    i_attisdropped = PQfnumber(res, "attisdropped");
+    i_attlen = PQfnumber(res, "attlen");
+    i_attalign = PQfnumber(res, "attalign");
+    i_attislocal = PQfnumber(res, "attislocal");
+    i_attnotnull = PQfnumber(res, "attnotnull");
+    i_attoptions = PQfnumber(res, "attoptions");
+    i_attcollation = PQfnumber(res, "attcollation");
+    i_attcompression = PQfnumber(res, "attcompression");
+    i_attfdwoptions = PQfnumber(res, "attfdwoptions");
+    i_attmissingval = PQfnumber(res, "attmissingval");
+    i_atthasdef = PQfnumber(res, "atthasdef");

-        res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
+    /* Within the next loop, we'll accumulate OIDs of tables with defaults */
+    resetPQExpBuffer(tbloids);
+    appendPQExpBufferChar(tbloids, '{');

-        ntups = PQntuples(res);
+    /*
+     * Outer loop iterates once per table, not once per row.  Incrementing of
+     * r is handled by the inner loop.
+     */
+    curtblindx = -1;
+    for (int r = 0; r < ntups;)
+    {
+        Oid            attrelid = atooid(PQgetvalue(res, r, i_attrelid));
+        TableInfo  *tbinfo = NULL;
+        int            numatts;
+        bool        hasdefaults;
+
+        /* Count rows for this table */
+        for (numatts = 1; numatts < ntups - r; numatts++)
+            if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
+                break;

-        tbinfo->numatts = ntups;
-        tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
-        tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
-        tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
-        tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
-        tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
-        tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
-        tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
-        tbinfo->attgenerated = (char *) pg_malloc(ntups * sizeof(char));
-        tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
-        tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
-        tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
-        tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
-        tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
-        tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
-        tbinfo->attcompression = (char *) pg_malloc(ntups * sizeof(char));
-        tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
-        tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
-        tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
-        tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
-        tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
+        /*
+         * Locate the associated TableInfo; we rely on tblinfo[] being in OID
+         * order.
+         */
+        while (++curtblindx < numTables)
+        {
+            tbinfo = &tblinfo[curtblindx];
+            if (tbinfo->dobj.catId.oid == attrelid)
+                break;
+        }
+        if (curtblindx >= numTables)
+            fatal("unrecognized table OID %u", attrelid);
+        /* cross-check that we only got requested tables */
+        if (tbinfo->relkind == RELKIND_SEQUENCE ||
+            !tbinfo->interesting)
+            fatal("unexpected column data for table \"%s\"",
+                  tbinfo->dobj.name);
+
+        /* Save data for this table */
+        tbinfo->numatts = numatts;
+        tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
+        tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
+        tbinfo->atttypmod = (int *) pg_malloc(numatts * sizeof(int));
+        tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
+        tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
+        tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
+        tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
+        tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
+        tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
+        tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
+        tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
+        tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
+        tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
+        tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
+        tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
+        tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
+        tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
+        tbinfo->notnull = (bool *) pg_malloc(numatts * sizeof(bool));
+        tbinfo->inhNotNull = (bool *) pg_malloc(numatts * sizeof(bool));
+        tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
         hasdefaults = false;

-        i_attnum = PQfnumber(res, "attnum");
-        i_attname = PQfnumber(res, "attname");
-        i_atttypname = PQfnumber(res, "atttypname");
-        i_atttypmod = PQfnumber(res, "atttypmod");
-        i_attstattarget = PQfnumber(res, "attstattarget");
-        i_attstorage = PQfnumber(res, "attstorage");
-        i_typstorage = PQfnumber(res, "typstorage");
-        i_attidentity = PQfnumber(res, "attidentity");
-        i_attgenerated = PQfnumber(res, "attgenerated");
-        i_attisdropped = PQfnumber(res, "attisdropped");
-        i_attlen = PQfnumber(res, "attlen");
-        i_attalign = PQfnumber(res, "attalign");
-        i_attislocal = PQfnumber(res, "attislocal");
-        i_attnotnull = PQfnumber(res, "attnotnull");
-        i_attoptions = PQfnumber(res, "attoptions");
-        i_attcollation = PQfnumber(res, "attcollation");
-        i_attcompression = PQfnumber(res, "attcompression");
-        i_attfdwoptions = PQfnumber(res, "attfdwoptions");
-        i_attmissingval = PQfnumber(res, "attmissingval");
-        i_atthasdef = PQfnumber(res, "atthasdef");
-
-        for (int j = 0; j < ntups; j++)
+        for (int j = 0; j < numatts; j++, r++)
         {
-            if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
+            if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
                 fatal("invalid column numbering in table \"%s\"",
                       tbinfo->dobj.name);
-            tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
-            tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
-            tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
-            tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
-            tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
-            tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
-            tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
-            tbinfo->attgenerated[j] = *(PQgetvalue(res, j, i_attgenerated));
+            tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
+            tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
+            tbinfo->atttypmod[j] = atoi(PQgetvalue(res, r, i_atttypmod));
+            tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
+            tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
+            tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
+            tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
+            tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
-            tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
-            tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
-            tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
-            tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
-            tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
-            tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
-            tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
-            tbinfo->attcompression[j] = *(PQgetvalue(res, j, i_attcompression));
-            tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
-            tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
+            tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
+            tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
+            tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
+            tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
+            tbinfo->notnull[j] = (PQgetvalue(res, r, i_attnotnull)[0] == 't');
+            tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
+            tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
+            tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
+            tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
+            tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
             tbinfo->attrdefs[j] = NULL; /* fix below */
-            if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
+            if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
                 hasdefaults = true;
             /* these flags will be set in flagInhAttrs() */
             tbinfo->inhNotNull[j] = false;
         }

-        PQclear(res);
-
-        /*
-         * Get info about column defaults.  This is skipped for a data-only
-         * dump, as it is only needed for table schemas.
-         */
-        if (!dopt->dataOnly && hasdefaults)
+        if (hasdefaults)
         {
-            AttrDefInfo *attrdefs;
-            int            numDefaults;
-
-            pg_log_info("finding default expressions of table \"%s.%s\"",
-                        tbinfo->dobj.namespace->dobj.name,
-                        tbinfo->dobj.name);
-
-            printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
-                              "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
-                              "FROM pg_catalog.pg_attrdef "
-                              "WHERE adrelid = '%u'::pg_catalog.oid",
-                              tbinfo->dobj.catId.oid);
-
-            res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
+            /* Collect OIDs of interesting tables that have defaults */
+            if (tbloids->len > 1)    /* do we have more than the '{'? */
+                appendPQExpBufferChar(tbloids, ',');
+            appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
+        }
+    }

-            numDefaults = PQntuples(res);
-            attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
+    PQclear(res);

-            for (int j = 0; j < numDefaults; j++)
-            {
-                int            adnum;
+    /*
+     * Now get info about column defaults.  This is skipped for a data-only
+     * dump, as it is only needed for table schemas.
+     */
+    if (!dopt->dataOnly && tbloids->len > 1)
+    {
+        AttrDefInfo *attrdefs;
+        int            numDefaults;
+        TableInfo  *tbinfo = NULL;

-                adnum = atoi(PQgetvalue(res, j, 2));
+        pg_log_info("finding table default expressions");

-                if (adnum <= 0 || adnum > ntups)
-                    fatal("invalid adnum value %d for table \"%s\"",
-                          adnum, tbinfo->dobj.name);
+        appendPQExpBufferChar(tbloids, '}');

-                /*
-                 * dropped columns shouldn't have defaults, but just in case,
-                 * ignore 'em
-                 */
-                if (tbinfo->attisdropped[adnum - 1])
-                    continue;
+        printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
+                          "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
+                          "ORDER BY a.adrelid, a.adnum",
+                          tbloids->data);

-                attrdefs[j].dobj.objType = DO_ATTRDEF;
-                attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
-                attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
-                AssignDumpId(&attrdefs[j].dobj);
-                attrdefs[j].adtable = tbinfo;
-                attrdefs[j].adnum = adnum;
-                attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
+        res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);

-                attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
-                attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
+        numDefaults = PQntuples(res);
+        attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));

-                attrdefs[j].dobj.dump = tbinfo->dobj.dump;
+        curtblindx = -1;
+        for (int j = 0; j < numDefaults; j++)
+        {
+            Oid            adtableoid = atooid(PQgetvalue(res, j, 0));
+            Oid            adoid = atooid(PQgetvalue(res, j, 1));
+            Oid            adrelid = atooid(PQgetvalue(res, j, 2));
+            int            adnum = atoi(PQgetvalue(res, j, 3));
+            char       *adsrc = PQgetvalue(res, j, 4);

-                /*
-                 * Figure out whether the default/generation expression should
-                 * be dumped as part of the main CREATE TABLE (or similar)
-                 * command or as a separate ALTER TABLE (or similar) command.
-                 * The preference is to put it into the CREATE command, but in
-                 * some cases that's not possible.
-                 */
-                if (tbinfo->attgenerated[adnum - 1])
-                {
-                    /*
-                     * Column generation expressions cannot be dumped
-                     * separately, because there is no syntax for it.  The
-                     * !shouldPrintColumn case below will be tempted to set
-                     * them to separate if they are attached to an inherited
-                     * column without a local definition, but that would be
-                     * wrong and unnecessary, because generation expressions
-                     * are always inherited, so there is no need to set them
-                     * again in child tables, and there is no syntax for it
-                     * either.  By setting separate to false here we prevent
-                     * the "default" from being processed as its own dumpable
-                     * object, and flagInhAttrs() will remove it from the
-                     * table when it detects that it belongs to an inherited
-                     * column.
-                     */
-                    attrdefs[j].separate = false;
-                }
-                else if (tbinfo->relkind == RELKIND_VIEW)
-                {
-                    /*
-                     * Defaults on a VIEW must always be dumped as separate
-                     * ALTER TABLE commands.
-                     */
-                    attrdefs[j].separate = true;
-                }
-                else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
-                {
-                    /* column will be suppressed, print default separately */
-                    attrdefs[j].separate = true;
-                }
-                else
+            /*
+             * Locate the associated TableInfo; we rely on tblinfo[] being in
+             * OID order.
+             */
+            if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
+            {
+                while (++curtblindx < numTables)
                 {
-                    attrdefs[j].separate = false;
+                    tbinfo = &tblinfo[curtblindx];
+                    if (tbinfo->dobj.catId.oid == adrelid)
+                        break;
                 }
+                if (curtblindx >= numTables)
+                    fatal("unrecognized table OID %u", adrelid);
+            }

-                if (!attrdefs[j].separate)
-                {
-                    /*
-                     * Mark the default as needing to appear before the table,
-                     * so that any dependencies it has must be emitted before
-                     * the CREATE TABLE.  If this is not possible, we'll
-                     * change to "separate" mode while sorting dependencies.
-                     */
-                    addObjectDependency(&tbinfo->dobj,
-                                        attrdefs[j].dobj.dumpId);
-                }
+            if (adnum <= 0 || adnum > tbinfo->numatts)
+                fatal("invalid adnum value %d for table \"%s\"",
+                      adnum, tbinfo->dobj.name);

-                tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
-            }
-            PQclear(res);
-        }
+            /*
+             * dropped columns shouldn't have defaults, but just in case,
+             * ignore 'em
+             */
+            if (tbinfo->attisdropped[adnum - 1])
+                continue;

-        /*
-         * Get info about table CHECK constraints.  This is skipped for a
-         * data-only dump, as it is only needed for table schemas.
-         */
-        if (tbinfo->ncheck > 0 && !dopt->dataOnly)
-        {
-            ConstraintInfo *constrs;
-            int            numConstrs;
+            attrdefs[j].dobj.objType = DO_ATTRDEF;
+            attrdefs[j].dobj.catId.tableoid = adtableoid;
+            attrdefs[j].dobj.catId.oid = adoid;
+            AssignDumpId(&attrdefs[j].dobj);
+            attrdefs[j].adtable = tbinfo;
+            attrdefs[j].adnum = adnum;
+            attrdefs[j].adef_expr = pg_strdup(adsrc);
+
+            attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
+            attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;

-            pg_log_info("finding check constraints for table \"%s.%s\"",
-                        tbinfo->dobj.namespace->dobj.name,
-                        tbinfo->dobj.name);
+            attrdefs[j].dobj.dump = tbinfo->dobj.dump;

-            resetPQExpBuffer(q);
-            if (fout->remoteVersion >= 90200)
+            /*
+             * Figure out whether the default/generation expression should be
+             * dumped as part of the main CREATE TABLE (or similar) command or
+             * as a separate ALTER TABLE (or similar) command. The preference
+             * is to put it into the CREATE command, but in some cases that's
+             * not possible.
+             */
+            if (tbinfo->attgenerated[adnum - 1])
+            {
+                /*
+                 * Column generation expressions cannot be dumped separately,
+                 * because there is no syntax for it.  The !shouldPrintColumn
+                 * case below will be tempted to set them to separate if they
+                 * are attached to an inherited column without a local
+                 * definition, but that would be wrong and unnecessary,
+                 * because generation expressions are always inherited, so
+                 * there is no need to set them again in child tables, and
+                 * there is no syntax for it either.  By setting separate to
+                 * false here we prevent the "default" from being processed as
+                 * its own dumpable object, and flagInhAttrs() will remove it
+                 * from the table when it detects that it belongs to an
+                 * inherited column.
+                 */
+                attrdefs[j].separate = false;
+            }
+            else if (tbinfo->relkind == RELKIND_VIEW)
             {
                 /*
-                 * convalidated is new in 9.2 (actually, it is there in 9.1,
-                 * but it wasn't ever false for check constraints until 9.2).
+                 * Defaults on a VIEW must always be dumped as separate ALTER
+                 * TABLE commands.
                  */
-                appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
-                                  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-                                  "conislocal, convalidated "
-                                  "FROM pg_catalog.pg_constraint "
-                                  "WHERE conrelid = '%u'::pg_catalog.oid "
-                                  "   AND contype = 'c' "
-                                  "ORDER BY conname",
-                                  tbinfo->dobj.catId.oid);
+                attrdefs[j].separate = true;
             }
-            else if (fout->remoteVersion >= 80400)
+            else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
             {
-                /* conislocal is new in 8.4 */
-                appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
-                                  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-                                  "conislocal, true AS convalidated "
-                                  "FROM pg_catalog.pg_constraint "
-                                  "WHERE conrelid = '%u'::pg_catalog.oid "
-                                  "   AND contype = 'c' "
-                                  "ORDER BY conname",
-                                  tbinfo->dobj.catId.oid);
+                /* column will be suppressed, print default separately */
+                attrdefs[j].separate = true;
             }
             else
             {
-                appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
-                                  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-                                  "true AS conislocal, true AS convalidated "
-                                  "FROM pg_catalog.pg_constraint "
-                                  "WHERE conrelid = '%u'::pg_catalog.oid "
-                                  "   AND contype = 'c' "
-                                  "ORDER BY conname",
-                                  tbinfo->dobj.catId.oid);
+                attrdefs[j].separate = false;
             }

-            res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
+            if (!attrdefs[j].separate)
+            {
+                /*
+                 * Mark the default as needing to appear before the table, so
+                 * that any dependencies it has must be emitted before the
+                 * CREATE TABLE.  If this is not possible, we'll change to
+                 * "separate" mode while sorting dependencies.
+                 */
+                addObjectDependency(&tbinfo->dobj,
+                                    attrdefs[j].dobj.dumpId);
+            }
+
+            tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
+        }
+
+        PQclear(res);
+    }

-            numConstrs = PQntuples(res);
-            if (numConstrs != tbinfo->ncheck)
+    /*
+     * Get info about table CHECK constraints.  This is skipped for a
+     * data-only dump, as it is only needed for table schemas.
+     */
+    if (!dopt->dataOnly && checkoids->len > 2)
+    {
+        ConstraintInfo *constrs;
+        int            numConstrs;
+        int            i_tableoid;
+        int            i_oid;
+        int            i_conrelid;
+        int            i_conname;
+        int            i_consrc;
+        int            i_conislocal;
+        int            i_convalidated;
+
+        pg_log_info("finding table check constraints");
+
+        resetPQExpBuffer(q);
+        appendPQExpBufferStr(q,
+                             "SELECT c.tableoid, c.oid, conrelid, conname, "
+                             "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, ");
+        if (fout->remoteVersion >= 90200)
+        {
+            /*
+             * convalidated is new in 9.2 (actually, it is there in 9.1, but
+             * it wasn't ever false for check constraints until 9.2).
+             */
+            appendPQExpBufferStr(q,
+                                 "conislocal, convalidated ");
+        }
+        else if (fout->remoteVersion >= 80400)
+        {
+            /* conislocal is new in 8.4 */
+            appendPQExpBufferStr(q,
+                                 "conislocal, true AS convalidated ");
+        }
+        else
+        {
+            appendPQExpBufferStr(q,
+                                 "true AS conislocal, true AS convalidated ");
+        }
+        appendPQExpBuffer(q,
+                          "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
+                          "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
+                          "WHERE contype = 'c' "
+                          "ORDER BY c.conrelid, c.conname",
+                          checkoids->data);
+
+        res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
+
+        numConstrs = PQntuples(res);
+        constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
+
+        i_tableoid = PQfnumber(res, "tableoid");
+        i_oid = PQfnumber(res, "oid");
+        i_conrelid = PQfnumber(res, "conrelid");
+        i_conname = PQfnumber(res, "conname");
+        i_consrc = PQfnumber(res, "consrc");
+        i_conislocal = PQfnumber(res, "conislocal");
+        i_convalidated = PQfnumber(res, "convalidated");
+
+        /* As above, this loop iterates once per table, not once per row */
+        curtblindx = -1;
+        for (int j = 0; j < numConstrs;)
+        {
+            Oid            conrelid = atooid(PQgetvalue(res, j, i_conrelid));
+            TableInfo  *tbinfo = NULL;
+            int            numcons;
+
+            /* Count rows for this table */
+            for (numcons = 1; numcons < numConstrs - j; numcons++)
+                if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
+                    break;
+
+            /*
+             * Locate the associated TableInfo; we rely on tblinfo[] being in
+             * OID order.
+             */
+            while (++curtblindx < numTables)
+            {
+                tbinfo = &tblinfo[curtblindx];
+                if (tbinfo->dobj.catId.oid == conrelid)
+                    break;
+            }
+            if (curtblindx >= numTables)
+                fatal("unrecognized table OID %u", conrelid);
+
+            if (numcons != tbinfo->ncheck)
             {
                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
                                       "expected %d check constraints on table \"%s\" but found %d",
                                       tbinfo->ncheck),
-                             tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
+                             tbinfo->ncheck, tbinfo->dobj.name, numcons);
                 pg_log_error("(The system catalogs might be corrupted.)");
                 exit_nicely(1);
             }

-            constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
-            tbinfo->checkexprs = constrs;
+            tbinfo->checkexprs = constrs + j;

-            for (int j = 0; j < numConstrs; j++)
+            for (int c = 0; c < numcons; c++, j++)
             {
-                bool        validated = PQgetvalue(res, j, 5)[0] == 't';
+                bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';

                 constrs[j].dobj.objType = DO_CONSTRAINT;
-                constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
-                constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
+                constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
+                constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
                 AssignDumpId(&constrs[j].dobj);
-                constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
+                constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
                 constrs[j].contable = tbinfo;
                 constrs[j].condomain = NULL;
                 constrs[j].contype = 'c';
-                constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
+                constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
                 constrs[j].confrelid = InvalidOid;
                 constrs[j].conindex = 0;
                 constrs[j].condeferrable = false;
                 constrs[j].condeferred = false;
-                constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
+                constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');

                 /*
                  * An unvalidated constraint needs to be dumped separately, so
@@ -8748,11 +8993,14 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                  * constraint must be split out from the table definition.
                  */
             }
-            PQclear(res);
         }
+
+        PQclear(res);
     }

     destroyPQExpBuffer(q);
+    destroyPQExpBuffer(tbloids);
+    destroyPQExpBuffer(checkoids);
 }

 /*
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 44114f3f71..27b95732c8 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1775,11 +1775,11 @@ connectDatabase(const char *dbname, const char *connection_string,
     my_version = PG_VERSION_NUM;

     /*
-     * We allow the server to be back to 8.0, and up to any minor release of
+     * We allow the server to be back to 8.4, and up to any minor release of
      * our own major version.  (See also version check in pg_dump.c.)
      */
     if (my_version != server_version
-        && (server_version < 80000 ||
+        && (server_version < 80400 ||
             (server_version / 100) > (my_version / 100)))
     {
         pg_log_error("server version: %s; %s version: %s",
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 8aa34c052d..515170682a 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2461,13 +2461,26 @@ dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
         /*
          * Set the TocEntry's dataLength in case we are doing a parallel dump
          * and want to order dump jobs by table size.  We choose to measure
-         * dataLength in table pages during dump, so no scaling is needed.
+         * dataLength in table pages (including TOAST pages) during dump, so
+         * no scaling is needed.
+         *
          * However, relpages is declared as "integer" in pg_class, and hence
          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
          * Cast so that we get the right interpretation of table sizes
          * exceeding INT_MAX pages.
          */
         te->dataLength = (BlockNumber) tbinfo->relpages;
+        te->dataLength += (BlockNumber) tbinfo->toastpages;
+
+        /*
+         * If pgoff_t is only 32 bits wide, the above refinement is useless,
+         * and instead we'd better worry about integer overflow.  Clamp to
+         * INT_MAX if the correct result exceeds that.
+         */
+        if (sizeof(te->dataLength) == 4 &&
+            (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
+             te->dataLength < 0))
+            te->dataLength = INT_MAX;
     }

     destroyPQExpBuffer(copyBuf);
@@ -6248,6 +6261,7 @@ getTables(Archive *fout, int *numTables)
     int            i_relhasindex;
     int            i_relhasrules;
     int            i_relpages;
+    int            i_toastpages;
     int            i_owning_tab;
     int            i_owning_col;
     int            i_reltablespace;
@@ -6297,6 +6311,7 @@ getTables(Archive *fout, int *numTables)
                       "(%s c.relowner) AS rolname, "
                       "c.relchecks, "
                       "c.relhasindex, c.relhasrules, c.relpages, "
+                      "tc.relpages AS toastpages, "
                       "d.refobjid AS owning_tab, "
                       "d.refobjsubid AS owning_col, "
                       "tsp.spcname AS reltablespace, ",
@@ -6453,17 +6468,14 @@ getTables(Archive *fout, int *numTables)
                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");

     /*
-     * We don't need any data from the TOAST table before 8.2.
-     *
      * We purposefully ignore toast OIDs for partitioned tables; the reason is
      * that versions 10 and 11 have them, but later versions do not, so
      * emitting them causes the upgrade to fail.
      */
-    if (fout->remoteVersion >= 80200)
-        appendPQExpBufferStr(query,
-                             "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
-                             " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
-                             " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
+    appendPQExpBufferStr(query,
+                         "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
+                         " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
+                         " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");

     /*
      * Restrict to interesting relkinds (in particular, not indexes).  Not all
@@ -6514,6 +6526,7 @@ getTables(Archive *fout, int *numTables)
     i_relhasindex = PQfnumber(res, "relhasindex");
     i_relhasrules = PQfnumber(res, "relhasrules");
     i_relpages = PQfnumber(res, "relpages");
+    i_toastpages = PQfnumber(res, "toastpages");
     i_owning_tab = PQfnumber(res, "owning_tab");
     i_owning_col = PQfnumber(res, "owning_col");
     i_reltablespace = PQfnumber(res, "reltablespace");
@@ -6575,6 +6588,10 @@ getTables(Archive *fout, int *numTables)
         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
+        if (PQgetisnull(res, i, i_toastpages))
+            tblinfo[i].toastpages = 0;
+        else
+            tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
         if (PQgetisnull(res, i, i_owning_tab))
         {
             tblinfo[i].owning_tab = InvalidOid;
@@ -10391,7 +10408,7 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
                  * about is allowing blob dumping to be parallelized, not just
                  * getting a smarter estimate for the single TOC entry.)
                  */
-                te->dataLength = MaxBlockNumber;
+                te->dataLength = INT_MAX;
             }
             break;
         case DO_POLICY:
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 291b880a97..6dccb4be4e 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -315,6 +315,7 @@ typedef struct _tableInfo
     int            owning_col;        /* attr # of column owning sequence */
     bool        is_identity_sequence;
     int            relpages;        /* table's size in pages (from pg_class) */
+    int            toastpages;        /* toast table's size in pages, if any */

     bool        interesting;    /* true if need to collect more data */
     bool        dummy_view;        /* view's real definition must be postponed */
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index 6af10a85a2..d3aac0dbdf 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -58,6 +58,23 @@ typedef enum _teSection
     SECTION_POST_DATA            /* stuff to be processed after data */
 } teSection;

+/* We need one enum entry per prepared query in pg_dump */
+enum _dumpPreparedQueries
+{
+    PREPQUERY_DUMPAGG,
+    PREPQUERY_DUMPBASETYPE,
+    PREPQUERY_DUMPCOMPOSITETYPE,
+    PREPQUERY_DUMPDOMAIN,
+    PREPQUERY_DUMPENUMTYPE,
+    PREPQUERY_DUMPFUNC,
+    PREPQUERY_DUMPOPR,
+    PREPQUERY_DUMPRANGETYPE,
+    PREPQUERY_DUMPTABLEATTACH,
+    PREPQUERY_GETCOLUMNACLS,
+    PREPQUERY_GETDOMAINCONSTRAINTS,
+    NUM_PREP_QUERIES            /* must be last */
+};
+
 /* Parameters needed by ConnectDatabase; same for dump and restore */
 typedef struct _connParams
 {
@@ -214,6 +231,9 @@ typedef struct Archive
     bool        exit_on_error;    /* whether to exit on SQL errors... */
     int            n_errors;        /* number of errors (if no die) */

+    /* prepared-query status */
+    bool       *is_prepared;    /* indexed by enum _dumpPreparedQueries */
+
     /* The rest is private */
 } Archive;

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 515170682a..10a86f9810 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1208,6 +1208,12 @@ setup_connection(Archive *AH, const char *dumpencoding,
             ExecuteSqlStatement(AH, "SET row_security = off");
     }

+    /*
+     * Initialize prepared-query state to "nothing prepared".  We do this here
+     * so that a parallel dump worker will have its own state.
+     */
+    AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
+
     /*
      * Start transaction-snapshot mode transaction to dump consistent data.
      */
@@ -7494,7 +7500,7 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
 {
     int            i;
     ConstraintInfo *constrinfo;
-    PQExpBuffer query;
+    PQExpBuffer query = createPQExpBuffer();
     PGresult   *res;
     int            i_tableoid,
                 i_oid,
@@ -7502,25 +7508,35 @@ getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
                 i_consrc;
     int            ntups;

-    query = createPQExpBuffer();
+    if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
+    {
+        /* Set up query for constraint-specific details */
+        appendPQExpBufferStr(query,
+                             "PREPARE getDomainConstraints(pg_catalog.oid) AS\n");
+
+        if (fout->remoteVersion >= 90100)
+            appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
+                                 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
+                                 "convalidated "
+                                 "FROM pg_catalog.pg_constraint "
+                                 "WHERE contypid = $1 "
+                                 "ORDER BY conname");
+        else
+            appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
+                                 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
+                                 "true as convalidated "
+                                 "FROM pg_catalog.pg_constraint "
+                                 "WHERE contypid = $1 "
+                                 "ORDER BY conname");

-    if (fout->remoteVersion >= 90100)
-        appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
-                          "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-                          "convalidated "
-                          "FROM pg_catalog.pg_constraint "
-                          "WHERE contypid = '%u'::pg_catalog.oid "
-                          "ORDER BY conname",
-                          tyinfo->dobj.catId.oid);
+        ExecuteSqlStatement(fout, query->data);

-    else
-        appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
-                          "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
-                          "true as convalidated "
-                          "FROM pg_catalog.pg_constraint "
-                          "WHERE contypid = '%u'::pg_catalog.oid "
-                          "ORDER BY conname",
-                          tyinfo->dobj.catId.oid);
+        fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
+    }
+
+    printfPQExpBuffer(query,
+                      "EXECUTE getDomainConstraints('%u')",
+                      tyinfo->dobj.catId.oid);

     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

@@ -10693,18 +10709,31 @@ dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
     int            i_enumlabel;
     int            i_oid;

-    if (fout->remoteVersion >= 90100)
-        appendPQExpBuffer(query, "SELECT oid, enumlabel "
-                          "FROM pg_catalog.pg_enum "
-                          "WHERE enumtypid = '%u'"
-                          "ORDER BY enumsortorder",
-                          tyinfo->dobj.catId.oid);
-    else
-        appendPQExpBuffer(query, "SELECT oid, enumlabel "
-                          "FROM pg_catalog.pg_enum "
-                          "WHERE enumtypid = '%u'"
-                          "ORDER BY oid",
-                          tyinfo->dobj.catId.oid);
+    if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
+    {
+        /* Set up query for enum-specific details */
+        appendPQExpBufferStr(query,
+                             "PREPARE dumpEnumType(pg_catalog.oid) AS\n");
+
+        if (fout->remoteVersion >= 90100)
+            appendPQExpBufferStr(query, "SELECT oid, enumlabel "
+                                 "FROM pg_catalog.pg_enum "
+                                 "WHERE enumtypid = $1 "
+                                 "ORDER BY enumsortorder");
+        else
+            appendPQExpBufferStr(query, "SELECT oid, enumlabel "
+                                 "FROM pg_catalog.pg_enum "
+                                 "WHERE enumtypid = $1 "
+                                 "ORDER BY oid");
+
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
+    }
+
+    printfPQExpBuffer(query,
+                      "EXECUTE dumpEnumType('%u')",
+                      tyinfo->dobj.catId.oid);

     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

@@ -10823,29 +10852,43 @@ dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
     char       *qualtypname;
     char       *procname;

-    appendPQExpBuffer(query,
-                      "SELECT ");
+    if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
+    {
+        /* Set up query for range-specific details */
+        appendPQExpBufferStr(query,
+                             "PREPARE dumpRangeType(pg_catalog.oid) AS\n");

-    if (fout->remoteVersion >= 140000)
-        appendPQExpBuffer(query,
-                          "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
-    else
-        appendPQExpBuffer(query,
-                          "NULL AS rngmultitype, ");
+        appendPQExpBufferStr(query,
+                             "SELECT ");

-    appendPQExpBuffer(query,
-                      "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
-                      "opc.opcname AS opcname, "
-                      "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
-                      "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
-                      "opc.opcdefault, "
-                      "CASE WHEN rngcollation = st.typcollation THEN 0 "
-                      "     ELSE rngcollation END AS collation, "
-                      "rngcanonical, rngsubdiff "
-                      "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
-                      "     pg_catalog.pg_opclass opc "
-                      "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
-                      "rngtypid = '%u'",
+        if (fout->remoteVersion >= 140000)
+            appendPQExpBufferStr(query,
+                                 "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
+        else
+            appendPQExpBufferStr(query,
+                                 "NULL AS rngmultitype, ");
+
+        appendPQExpBufferStr(query,
+                             "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
+                             "opc.opcname AS opcname, "
+                             "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
+                             "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
+                             "opc.opcdefault, "
+                             "CASE WHEN rngcollation = st.typcollation THEN 0 "
+                             "     ELSE rngcollation END AS collation, "
+                             "rngcanonical, rngsubdiff "
+                             "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
+                             "     pg_catalog.pg_opclass opc "
+                             "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
+                             "rngtypid = $1");
+
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
+    }
+
+    printfPQExpBuffer(query,
+                      "EXECUTE dumpRangeType('%u')",
                       tyinfo->dobj.catId.oid);

     res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -11053,55 +11096,68 @@ dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
     char       *typdefault;
     bool        typdefault_is_literal = false;

-    /* Fetch type-specific details */
-    appendPQExpBufferStr(query, "SELECT typlen, "
-                         "typinput, typoutput, typreceive, typsend, "
-                         "typreceive::pg_catalog.oid AS typreceiveoid, "
-                         "typsend::pg_catalog.oid AS typsendoid, "
-                         "typanalyze, "
-                         "typanalyze::pg_catalog.oid AS typanalyzeoid, "
-                         "typdelim, typbyval, typalign, typstorage, ");
-
-    if (fout->remoteVersion >= 80300)
-        appendPQExpBufferStr(query,
-                             "typmodin, typmodout, "
-                             "typmodin::pg_catalog.oid AS typmodinoid, "
-                             "typmodout::pg_catalog.oid AS typmodoutoid, ");
-    else
+    if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
+    {
+        /* Set up query for type-specific details */
         appendPQExpBufferStr(query,
-                             "'-' AS typmodin, '-' AS typmodout, "
-                             "0 AS typmodinoid, 0 AS typmodoutoid, ");
+                             "PREPARE dumpBaseType(pg_catalog.oid) AS\n");

-    if (fout->remoteVersion >= 80400)
-        appendPQExpBufferStr(query,
-                             "typcategory, typispreferred, ");
-    else
-        appendPQExpBufferStr(query,
-                             "'U' AS typcategory, false AS typispreferred, ");
+        appendPQExpBufferStr(query, "SELECT typlen, "
+                             "typinput, typoutput, typreceive, typsend, "
+                             "typreceive::pg_catalog.oid AS typreceiveoid, "
+                             "typsend::pg_catalog.oid AS typsendoid, "
+                             "typanalyze, "
+                             "typanalyze::pg_catalog.oid AS typanalyzeoid, "
+                             "typdelim, typbyval, typalign, typstorage, ");

-    if (fout->remoteVersion >= 90100)
-        appendPQExpBufferStr(query, "(typcollation <> 0) AS typcollatable, ");
-    else
-        appendPQExpBufferStr(query, "false AS typcollatable, ");
+        if (fout->remoteVersion >= 80300)
+            appendPQExpBufferStr(query,
+                                 "typmodin, typmodout, "
+                                 "typmodin::pg_catalog.oid AS typmodinoid, "
+                                 "typmodout::pg_catalog.oid AS typmodoutoid, ");
+        else
+            appendPQExpBufferStr(query,
+                                 "'-' AS typmodin, '-' AS typmodout, "
+                                 "0 AS typmodinoid, 0 AS typmodoutoid, ");

-    if (fout->remoteVersion >= 140000)
-        appendPQExpBufferStr(query,
-                             "typsubscript, "
-                             "typsubscript::pg_catalog.oid AS typsubscriptoid, ");
-    else
-        appendPQExpBufferStr(query,
-                             "'-' AS typsubscript, 0 AS typsubscriptoid, ");
+        if (fout->remoteVersion >= 80400)
+            appendPQExpBufferStr(query,
+                                 "typcategory, typispreferred, ");
+        else
+            appendPQExpBufferStr(query,
+                                 "'U' AS typcategory, false AS typispreferred, ");

-    /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
-    if (fout->remoteVersion >= 80400)
-        appendPQExpBufferStr(query,
-                             "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault ");
-    else
-        appendPQExpBufferStr(query,
-                             "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS
typdefaultbin,typdefault "); 
+        if (fout->remoteVersion >= 90100)
+            appendPQExpBufferStr(query, "(typcollation <> 0) AS typcollatable, ");
+        else
+            appendPQExpBufferStr(query, "false AS typcollatable, ");

-    appendPQExpBuffer(query, "FROM pg_catalog.pg_type "
-                      "WHERE oid = '%u'::pg_catalog.oid",
+        if (fout->remoteVersion >= 140000)
+            appendPQExpBufferStr(query,
+                                 "typsubscript, "
+                                 "typsubscript::pg_catalog.oid AS typsubscriptoid, ");
+        else
+            appendPQExpBufferStr(query,
+                                 "'-' AS typsubscript, 0 AS typsubscriptoid, ");
+
+        /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
+        if (fout->remoteVersion >= 80400)
+            appendPQExpBufferStr(query,
+                                 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault ");
+        else
+            appendPQExpBufferStr(query,
+                                 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS
typdefaultbin,typdefault "); 
+
+        appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
+                             "WHERE oid = $1");
+
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
+    }
+
+    printfPQExpBuffer(query,
+                      "EXECUTE dumpBaseType('%u')",
                       tyinfo->dobj.catId.oid);

     res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -11296,32 +11352,44 @@ dumpDomain(Archive *fout, const TypeInfo *tyinfo)
     Oid            typcollation;
     bool        typdefault_is_literal = false;

-    /* Fetch domain specific details */
-    if (fout->remoteVersion >= 90100)
+    if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
     {
-        /* typcollation is new in 9.1 */
-        appendPQExpBuffer(query, "SELECT t.typnotnull, "
-                          "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
-                          "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS
typdefaultbin," 
-                          "t.typdefault, "
-                          "CASE WHEN t.typcollation <> u.typcollation "
-                          "THEN t.typcollation ELSE 0 END AS typcollation "
-                          "FROM pg_catalog.pg_type t "
-                          "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
-                          "WHERE t.oid = '%u'::pg_catalog.oid",
-                          tyinfo->dobj.catId.oid);
-    }
-    else
-    {
-        appendPQExpBuffer(query, "SELECT typnotnull, "
-                          "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
-                          "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS
typdefaultbin," 
-                          "typdefault, 0 AS typcollation "
-                          "FROM pg_catalog.pg_type "
-                          "WHERE oid = '%u'::pg_catalog.oid",
-                          tyinfo->dobj.catId.oid);
+        /* Set up query for domain-specific details */
+        appendPQExpBufferStr(query,
+                             "PREPARE dumpDomain(pg_catalog.oid) AS\n");
+
+        if (fout->remoteVersion >= 90100)
+        {
+            /* typcollation is new in 9.1 */
+            appendPQExpBufferStr(query, "SELECT t.typnotnull, "
+                                 "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
+                                 "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass)
AStypdefaultbin, " 
+                                 "t.typdefault, "
+                                 "CASE WHEN t.typcollation <> u.typcollation "
+                                 "THEN t.typcollation ELSE 0 END AS typcollation "
+                                 "FROM pg_catalog.pg_type t "
+                                 "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
+                                 "WHERE t.oid = $1");
+        }
+        else
+        {
+            appendPQExpBufferStr(query, "SELECT typnotnull, "
+                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
+                                 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS
typdefaultbin," 
+                                 "typdefault, 0 AS typcollation "
+                                 "FROM pg_catalog.pg_type "
+                                 "WHERE oid = $1");
+        }
+
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
     }

+    printfPQExpBuffer(query,
+                      "EXECUTE dumpDomain('%u')",
+                      tyinfo->dobj.catId.oid);
+
     res = ExecuteSqlQueryForSingleRow(fout, query->data);

     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
@@ -11474,45 +11542,57 @@ dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
     int            i;
     int            actual_atts;

-    /* Fetch type specific details */
-    if (fout->remoteVersion >= 90100)
-    {
-        /*
-         * attcollation is new in 9.1.  Since we only want to dump COLLATE
-         * clauses for attributes whose collation is different from their
-         * type's default, we use a CASE here to suppress uninteresting
-         * attcollations cheaply.  atttypid will be 0 for dropped columns;
-         * collation does not matter for those.
-         */
-        appendPQExpBuffer(query, "SELECT a.attname, "
-                          "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
-                          "a.attlen, a.attalign, a.attisdropped, "
-                          "CASE WHEN a.attcollation <> at.typcollation "
-                          "THEN a.attcollation ELSE 0 END AS attcollation "
-                          "FROM pg_catalog.pg_type ct "
-                          "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
-                          "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
-                          "WHERE ct.oid = '%u'::pg_catalog.oid "
-                          "ORDER BY a.attnum ",
-                          tyinfo->dobj.catId.oid);
-    }
-    else
+    if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
     {
-        /*
-         * Since ALTER TYPE could not drop columns until 9.1, attisdropped
-         * should always be false.
-         */
-        appendPQExpBuffer(query, "SELECT a.attname, "
-                          "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
-                          "a.attlen, a.attalign, a.attisdropped, "
-                          "0 AS attcollation "
-                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
-                          "WHERE ct.oid = '%u'::pg_catalog.oid "
-                          "AND a.attrelid = ct.typrelid "
-                          "ORDER BY a.attnum ",
-                          tyinfo->dobj.catId.oid);
+        /* Set up query for type-specific details */
+        appendPQExpBufferStr(query,
+                             "PREPARE dumpCompositeType(pg_catalog.oid) AS\n");
+
+        if (fout->remoteVersion >= 90100)
+        {
+            /*
+             * attcollation is new in 9.1.  Since we only want to dump COLLATE
+             * clauses for attributes whose collation is different from their
+             * type's default, we use a CASE here to suppress uninteresting
+             * attcollations cheaply.  atttypid will be 0 for dropped columns;
+             * collation does not matter for those.
+             */
+            appendPQExpBufferStr(query, "SELECT a.attname, "
+                                 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
+                                 "a.attlen, a.attalign, a.attisdropped, "
+                                 "CASE WHEN a.attcollation <> at.typcollation "
+                                 "THEN a.attcollation ELSE 0 END AS attcollation "
+                                 "FROM pg_catalog.pg_type ct "
+                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
+                                 "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
+                                 "WHERE ct.oid = $1 "
+                                 "ORDER BY a.attnum");
+        }
+        else
+        {
+            /*
+             * Since ALTER TYPE could not drop columns until 9.1, attisdropped
+             * should always be false.
+             */
+            appendPQExpBufferStr(query, "SELECT a.attname, "
+                                 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
+                                 "a.attlen, a.attalign, a.attisdropped, "
+                                 "0 AS attcollation "
+                                 "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
+                                 "WHERE ct.oid = $1 "
+                                 "AND a.attrelid = ct.typrelid "
+                                 "ORDER BY a.attnum");
+        }
+
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
     }

+    printfPQExpBuffer(query,
+                      "EXECUTE dumpCompositeType('%u')",
+                      tyinfo->dobj.catId.oid);
+
     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

     ntups = PQntuples(res);
@@ -12131,96 +12211,109 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
     delqry = createPQExpBuffer();
     asPart = createPQExpBuffer();

-    /* Fetch function-specific details */
-    appendPQExpBufferStr(query,
-                         "SELECT\n"
-                         "proretset,\n"
-                         "prosrc,\n"
-                         "probin,\n"
-                         "provolatile,\n"
-                         "proisstrict,\n"
-                         "prosecdef,\n"
-                         "lanname,\n");
-
-    if (fout->remoteVersion >= 80300)
-        appendPQExpBufferStr(query,
-                             "proconfig,\n"
-                             "procost,\n"
-                             "prorows,\n");
-    else
-        appendPQExpBufferStr(query,
-                             "null AS proconfig,\n"
-                             "0 AS procost,\n"
-                             "0 AS prorows,\n");
-
-    if (fout->remoteVersion >= 80400)
+    if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
     {
-        /*
-         * In 8.4 and up we rely on pg_get_function_arguments and
-         * pg_get_function_result instead of examining proallargtypes etc.
-         */
+        /* Set up query for function-specific details */
         appendPQExpBufferStr(query,
-                             "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
-                             "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
-                             "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n");
-    }
-    else if (fout->remoteVersion >= 80100)
-        appendPQExpBufferStr(query,
-                             "proallargtypes,\n"
-                             "proargmodes,\n"
-                             "proargnames,\n");
-    else
-        appendPQExpBufferStr(query,
-                             "null AS proallargtypes,\n"
-                             "null AS proargmodes,\n"
-                             "proargnames,\n");
+                             "PREPARE dumpFunc(pg_catalog.oid) AS\n");

-    if (fout->remoteVersion >= 90200)
-        appendPQExpBufferStr(query,
-                             "proleakproof,\n");
-    else
         appendPQExpBufferStr(query,
-                             "false AS proleakproof,\n");
+                             "SELECT\n"
+                             "proretset,\n"
+                             "prosrc,\n"
+                             "probin,\n"
+                             "provolatile,\n"
+                             "proisstrict,\n"
+                             "prosecdef,\n"
+                             "lanname,\n");
+
+        if (fout->remoteVersion >= 80300)
+            appendPQExpBufferStr(query,
+                                 "proconfig,\n"
+                                 "procost,\n"
+                                 "prorows,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "null AS proconfig,\n"
+                                 "0 AS procost,\n"
+                                 "0 AS prorows,\n");

-    if (fout->remoteVersion >= 90500)
-        appendPQExpBufferStr(query,
-                             "array_to_string(protrftypes, ' ') AS protrftypes,\n");
+        if (fout->remoteVersion >= 80400)
+        {
+            /*
+             * In 8.4 and up we rely on pg_get_function_arguments and
+             * pg_get_function_result instead of examining proallargtypes etc.
+             */
+            appendPQExpBufferStr(query,
+                                 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
+                                 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
+                                 "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n");
+        }
+        else if (fout->remoteVersion >= 80100)
+            appendPQExpBufferStr(query,
+                                 "proallargtypes,\n"
+                                 "proargmodes,\n"
+                                 "proargnames,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "null AS proallargtypes,\n"
+                                 "null AS proargmodes,\n"
+                                 "proargnames,\n");

-    if (fout->remoteVersion >= 90600)
-        appendPQExpBufferStr(query,
-                             "proparallel,\n");
-    else
-        appendPQExpBufferStr(query,
-                             "'u' AS proparallel,\n");
+        if (fout->remoteVersion >= 90200)
+            appendPQExpBufferStr(query,
+                                 "proleakproof,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "false AS proleakproof,\n");

-    if (fout->remoteVersion >= 110000)
-        appendPQExpBufferStr(query,
-                             "prokind,\n");
-    else if (fout->remoteVersion >= 80400)
-        appendPQExpBufferStr(query,
-                             "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
-    else
-        appendPQExpBufferStr(query,
-                             "'f' AS prokind,\n");
+        if (fout->remoteVersion >= 90500)
+            appendPQExpBufferStr(query,
+                                 "array_to_string(protrftypes, ' ') AS protrftypes,\n");

-    if (fout->remoteVersion >= 120000)
-        appendPQExpBufferStr(query,
-                             "prosupport,\n");
-    else
-        appendPQExpBufferStr(query,
-                             "'-' AS prosupport,\n");
+        if (fout->remoteVersion >= 90600)
+            appendPQExpBufferStr(query,
+                                 "proparallel,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "'u' AS proparallel,\n");
+
+        if (fout->remoteVersion >= 110000)
+            appendPQExpBufferStr(query,
+                                 "prokind,\n");
+        else if (fout->remoteVersion >= 80400)
+            appendPQExpBufferStr(query,
+                                 "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "'f' AS prokind,\n");
+
+        if (fout->remoteVersion >= 120000)
+            appendPQExpBufferStr(query,
+                                 "prosupport,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "'-' AS prosupport,\n");
+
+        if (fout->remoteVersion >= 140000)
+            appendPQExpBufferStr(query,
+                                 "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "NULL AS prosqlbody\n");

-    if (fout->remoteVersion >= 140000)
-        appendPQExpBufferStr(query,
-                             "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
-    else
         appendPQExpBufferStr(query,
-                             "NULL AS prosqlbody\n");
+                             "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
+                             "WHERE p.oid = $1 "
+                             "AND l.oid = p.prolang");

-    appendPQExpBuffer(query,
-                      "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
-                      "WHERE p.oid = '%u'::pg_catalog.oid "
-                      "AND l.oid = p.prolang",
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
+    }
+
+    printfPQExpBuffer(query,
+                      "EXECUTE dumpFunc('%u')",
                       finfo->dobj.catId.oid);

     res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -12887,38 +12980,51 @@ dumpOpr(Archive *fout, const OprInfo *oprinfo)
     oprid = createPQExpBuffer();
     details = createPQExpBuffer();

-    if (fout->remoteVersion >= 80300)
-    {
-        appendPQExpBuffer(query, "SELECT oprkind, "
-                          "oprcode::pg_catalog.regprocedure, "
-                          "oprleft::pg_catalog.regtype, "
-                          "oprright::pg_catalog.regtype, "
-                          "oprcom, "
-                          "oprnegate, "
-                          "oprrest::pg_catalog.regprocedure, "
-                          "oprjoin::pg_catalog.regprocedure, "
-                          "oprcanmerge, oprcanhash "
-                          "FROM pg_catalog.pg_operator "
-                          "WHERE oid = '%u'::pg_catalog.oid",
-                          oprinfo->dobj.catId.oid);
-    }
-    else
+    if (!fout->is_prepared[PREPQUERY_DUMPOPR])
     {
-        appendPQExpBuffer(query, "SELECT oprkind, "
-                          "oprcode::pg_catalog.regprocedure, "
-                          "oprleft::pg_catalog.regtype, "
-                          "oprright::pg_catalog.regtype, "
-                          "oprcom, "
-                          "oprnegate, "
-                          "oprrest::pg_catalog.regprocedure, "
-                          "oprjoin::pg_catalog.regprocedure, "
-                          "(oprlsortop != 0) AS oprcanmerge, "
-                          "oprcanhash "
-                          "FROM pg_catalog.pg_operator "
-                          "WHERE oid = '%u'::pg_catalog.oid",
-                          oprinfo->dobj.catId.oid);
+        /* Set up query for operator-specific details */
+        appendPQExpBufferStr(query,
+                             "PREPARE dumpOpr(pg_catalog.oid) AS\n");
+
+        if (fout->remoteVersion >= 80300)
+        {
+            appendPQExpBufferStr(query, "SELECT oprkind, "
+                                 "oprcode::pg_catalog.regprocedure, "
+                                 "oprleft::pg_catalog.regtype, "
+                                 "oprright::pg_catalog.regtype, "
+                                 "oprcom, "
+                                 "oprnegate, "
+                                 "oprrest::pg_catalog.regprocedure, "
+                                 "oprjoin::pg_catalog.regprocedure, "
+                                 "oprcanmerge, oprcanhash "
+                                 "FROM pg_catalog.pg_operator "
+                                 "WHERE oid = $1");
+        }
+        else
+        {
+            appendPQExpBufferStr(query, "SELECT oprkind, "
+                                 "oprcode::pg_catalog.regprocedure, "
+                                 "oprleft::pg_catalog.regtype, "
+                                 "oprright::pg_catalog.regtype, "
+                                 "oprcom, "
+                                 "oprnegate, "
+                                 "oprrest::pg_catalog.regprocedure, "
+                                 "oprjoin::pg_catalog.regprocedure, "
+                                 "(oprlsortop != 0) AS oprcanmerge, "
+                                 "oprcanhash "
+                                 "FROM pg_catalog.pg_operator "
+                                 "WHERE oid = $1");
+        }
+
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPOPR] = true;
     }

+    printfPQExpBuffer(query,
+                      "EXECUTE dumpOpr('%u')",
+                      oprinfo->dobj.catId.oid);
+
     res = ExecuteSqlQueryForSingleRow(fout, query->data);

     i_oprkind = PQfnumber(res, "oprkind");
@@ -14184,77 +14290,90 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
     delq = createPQExpBuffer();
     details = createPQExpBuffer();

-    /* Get aggregate-specific details */
-    appendPQExpBufferStr(query,
-                         "SELECT\n"
-                         "aggtransfn,\n"
-                         "aggfinalfn,\n"
-                         "aggtranstype::pg_catalog.regtype,\n"
-                         "agginitval,\n");
-
-    if (fout->remoteVersion >= 80100)
-        appendPQExpBufferStr(query,
-                             "aggsortop,\n");
-    else
+    if (!fout->is_prepared[PREPQUERY_DUMPAGG])
+    {
+        /* Set up query for aggregate-specific details */
         appendPQExpBufferStr(query,
-                             "0 AS aggsortop,\n");
+                             "PREPARE dumpAgg(pg_catalog.oid) AS\n");

-    if (fout->remoteVersion >= 80400)
         appendPQExpBufferStr(query,
-                             "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
-                             "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
+                             "SELECT "
+                             "aggtransfn,\n"
+                             "aggfinalfn,\n"
+                             "aggtranstype::pg_catalog.regtype,\n"
+                             "agginitval,\n");

-    if (fout->remoteVersion >= 90400)
-        appendPQExpBufferStr(query,
-                             "aggkind,\n"
-                             "aggmtransfn,\n"
-                             "aggminvtransfn,\n"
-                             "aggmfinalfn,\n"
-                             "aggmtranstype::pg_catalog.regtype,\n"
-                             "aggfinalextra,\n"
-                             "aggmfinalextra,\n"
-                             "aggtransspace,\n"
-                             "aggmtransspace,\n"
-                             "aggminitval,\n");
-    else
-        appendPQExpBufferStr(query,
-                             "'n' AS aggkind,\n"
-                             "'-' AS aggmtransfn,\n"
-                             "'-' AS aggminvtransfn,\n"
-                             "'-' AS aggmfinalfn,\n"
-                             "0 AS aggmtranstype,\n"
-                             "false AS aggfinalextra,\n"
-                             "false AS aggmfinalextra,\n"
-                             "0 AS aggtransspace,\n"
-                             "0 AS aggmtransspace,\n"
-                             "NULL AS aggminitval,\n");
+        if (fout->remoteVersion >= 80100)
+            appendPQExpBufferStr(query,
+                                 "aggsortop,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "0 AS aggsortop,\n");

-    if (fout->remoteVersion >= 90600)
-        appendPQExpBufferStr(query,
-                             "aggcombinefn,\n"
-                             "aggserialfn,\n"
-                             "aggdeserialfn,\n"
-                             "proparallel,\n");
-    else
-        appendPQExpBufferStr(query,
-                             "'-' AS aggcombinefn,\n"
-                             "'-' AS aggserialfn,\n"
-                             "'-' AS aggdeserialfn,\n"
-                             "'u' AS proparallel,\n");
+        if (fout->remoteVersion >= 80400)
+            appendPQExpBufferStr(query,
+                                 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
+                                 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
+
+        if (fout->remoteVersion >= 90400)
+            appendPQExpBufferStr(query,
+                                 "aggkind,\n"
+                                 "aggmtransfn,\n"
+                                 "aggminvtransfn,\n"
+                                 "aggmfinalfn,\n"
+                                 "aggmtranstype::pg_catalog.regtype,\n"
+                                 "aggfinalextra,\n"
+                                 "aggmfinalextra,\n"
+                                 "aggtransspace,\n"
+                                 "aggmtransspace,\n"
+                                 "aggminitval,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "'n' AS aggkind,\n"
+                                 "'-' AS aggmtransfn,\n"
+                                 "'-' AS aggminvtransfn,\n"
+                                 "'-' AS aggmfinalfn,\n"
+                                 "0 AS aggmtranstype,\n"
+                                 "false AS aggfinalextra,\n"
+                                 "false AS aggmfinalextra,\n"
+                                 "0 AS aggtransspace,\n"
+                                 "0 AS aggmtransspace,\n"
+                                 "NULL AS aggminitval,\n");
+
+        if (fout->remoteVersion >= 90600)
+            appendPQExpBufferStr(query,
+                                 "aggcombinefn,\n"
+                                 "aggserialfn,\n"
+                                 "aggdeserialfn,\n"
+                                 "proparallel,\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "'-' AS aggcombinefn,\n"
+                                 "'-' AS aggserialfn,\n"
+                                 "'-' AS aggdeserialfn,\n"
+                                 "'u' AS proparallel,\n");
+
+        if (fout->remoteVersion >= 110000)
+            appendPQExpBufferStr(query,
+                                 "aggfinalmodify,\n"
+                                 "aggmfinalmodify\n");
+        else
+            appendPQExpBufferStr(query,
+                                 "'0' AS aggfinalmodify,\n"
+                                 "'0' AS aggmfinalmodify\n");

-    if (fout->remoteVersion >= 110000)
-        appendPQExpBufferStr(query,
-                             "aggfinalmodify,\n"
-                             "aggmfinalmodify\n");
-    else
         appendPQExpBufferStr(query,
-                             "'0' AS aggfinalmodify,\n"
-                             "'0' AS aggmfinalmodify\n");
+                             "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
+                             "WHERE a.aggfnoid = p.oid "
+                             "AND p.oid = $1");

-    appendPQExpBuffer(query,
-                      "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
-                      "WHERE a.aggfnoid = p.oid "
-                      "AND p.oid = '%u'::pg_catalog.oid",
+        ExecuteSqlStatement(fout, query->data);
+
+        fout->is_prepared[PREPQUERY_DUMPAGG] = true;
+    }
+
+    printfPQExpBuffer(query,
+                      "EXECUTE dumpAgg('%u')",
                       agginfo->aggfn.dobj.catId.oid);

     res = ExecuteSqlQueryForSingleRow(fout, query->data);
@@ -15668,46 +15787,59 @@ dumpTable(Archive *fout, const TableInfo *tbinfo)
         PGresult   *res;
         int            i;

-        if (fout->remoteVersion >= 90600)
+        if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
         {
-            /*
-             * In principle we should call acldefault('c', relowner) to get
-             * the default ACL for a column.  However, we don't currently
-             * store the numeric OID of the relowner in TableInfo.  We could
-             * convert the owner name using regrole, but that creates a risk
-             * of failure due to concurrent role renames.  Given that the
-             * default ACL for columns is empty and is likely to stay that
-             * way, it's not worth extra cycles and risk to avoid hard-wiring
-             * that knowledge here.
-             */
-            appendPQExpBuffer(query,
-                              "SELECT at.attname, "
-                              "at.attacl, "
-                              "'{}' AS acldefault, "
-                              "pip.privtype, pip.initprivs "
-                              "FROM pg_catalog.pg_attribute at "
-                              "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'::pg_catalog.oid AND "
-                              "NOT at.attisdropped "
-                              "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
-                              "ORDER BY at.attnum",
-                              tbinfo->dobj.catId.oid);
-        }
-        else
-        {
-            appendPQExpBuffer(query,
-                              "SELECT attname, attacl, '{}' AS acldefault, "
-                              "NULL AS privtype, NULL AS initprivs "
-                              "FROM pg_catalog.pg_attribute "
-                              "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
-                              "AND attacl IS NOT NULL "
-                              "ORDER BY attnum",
-                              tbinfo->dobj.catId.oid);
+            /* Set up query for column ACLs */
+            appendPQExpBufferStr(query,
+                                 "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
+
+            if (fout->remoteVersion >= 90600)
+            {
+                /*
+                 * In principle we should call acldefault('c', relowner) to
+                 * get the default ACL for a column.  However, we don't
+                 * currently store the numeric OID of the relowner in
+                 * TableInfo.  We could convert the owner name using regrole,
+                 * but that creates a risk of failure due to concurrent role
+                 * renames.  Given that the default ACL for columns is empty
+                 * and is likely to stay that way, it's not worth extra cycles
+                 * and risk to avoid hard-wiring that knowledge here.
+                 */
+                appendPQExpBufferStr(query,
+                                     "SELECT at.attname, "
+                                     "at.attacl, "
+                                     "'{}' AS acldefault, "
+                                     "pip.privtype, pip.initprivs "
+                                     "FROM pg_catalog.pg_attribute at "
+                                     "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 = $1 AND "
+                                     "NOT at.attisdropped "
+                                     "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
+                                     "ORDER BY at.attnum");
+            }
+            else
+            {
+                appendPQExpBufferStr(query,
+                                     "SELECT attname, attacl, '{}' AS acldefault, "
+                                     "NULL AS privtype, NULL AS initprivs "
+                                     "FROM pg_catalog.pg_attribute "
+                                     "WHERE attrelid = $1 AND NOT attisdropped "
+                                     "AND attacl IS NOT NULL "
+                                     "ORDER BY attnum");
+            }
+
+            ExecuteSqlStatement(fout, query->data);
+
+            fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
         }

+        printfPQExpBuffer(query,
+                          "EXECUTE getColumnACLs('%u')",
+                          tbinfo->dobj.catId.oid);
+
         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);

         for (i = 0; i < PQntuples(res); i++)
@@ -16656,12 +16788,26 @@ dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)

     q = createPQExpBuffer();

-    /* Fetch the partition's partbound */
-    appendPQExpBuffer(q,
-                      "SELECT pg_get_expr(c.relpartbound, c.oid) "
-                      "FROM pg_class c "
-                      "WHERE c.oid = '%u'",
+    if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
+    {
+        /* Set up query for partbound details */
+        appendPQExpBufferStr(q,
+                             "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
+
+        appendPQExpBufferStr(q,
+                             "SELECT pg_get_expr(c.relpartbound, c.oid) "
+                             "FROM pg_class c "
+                             "WHERE c.oid = $1");
+
+        ExecuteSqlStatement(fout, q->data);
+
+        fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
+    }
+
+    printfPQExpBuffer(q,
+                      "EXECUTE dumpTableAttach('%u')",
                       attachinfo->partitionTbl->dobj.catId.oid);
+
     res = ExecuteSqlQueryForSingleRow(fout, q->data);
     partbound = PQgetvalue(res, 0, 0);


В списке pgsql-hackers по дате отправления:

Предыдущее
От: Peter Eisentraut
Дата:
Сообщение: Transparent column encryption
Следующее
От: Chapman Flack
Дата:
Сообщение: Re: The "char" type versus non-ASCII characters