]> granicus.if.org Git - postgresql/blobdiff - src/bin/pg_dump/pg_dump.c
Un-break pg_dump for pre-8.3 source servers.
[postgresql] / src / bin / pg_dump / pg_dump.c
index 20e8aedb1913fa6012fac1d57883a96408d7894d..be25e94cb2007bdefe5ebf700ed6b3870002c891 100644 (file)
@@ -4,7 +4,7 @@
  *       pg_dump is a utility for dumping out a postgres database
  *       into a script file.
  *
- * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *     pg_dump will read the system catalogs in a database and dump out a
@@ -33,6 +33,7 @@
 
 #include <unistd.h>
 #include <ctype.h>
+#include <limits.h>
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
 #endif
@@ -54,6 +55,7 @@
 #include "catalog/pg_trigger_d.h"
 #include "catalog/pg_type_d.h"
 #include "libpq/libpq-fs.h"
+#include "storage/block.h"
 
 #include "dumputils.h"
 #include "parallel.h"
@@ -90,8 +92,6 @@ typedef enum OidOptions
 } OidOptions;
 
 /* global decls */
-bool           g_verbose;                      /* User wants verbose narration of our
-                                                                * activities. */
 static bool dosync = true;             /* Issue fsync() to make dump durable on disk. */
 
 /* subquery used to convert user ID (eg, datdba) to user name */
@@ -133,43 +133,51 @@ char              g_comment_end[10];
 
 static const CatalogId nilCatalogId = {0, 0};
 
+/* override for standard extra_float_digits setting */
+static bool have_extra_float_digits = false;
+static int     extra_float_digits;
+
+/*
+ * The default number of rows per INSERT when
+ * --inserts is specified without --rows-per-insert
+ */
+#define DUMP_DEFAULT_ROWS_PER_INSERT 1
+
 /*
  * Macro for producing quoted, schema-qualified name of a dumpable object.
- * Note implicit dependence on "fout"; we should get rid of that argument.
  */
 #define fmtQualifiedDumpable(obj) \
-       fmtQualifiedId(fout->remoteVersion, \
-                                  (obj)->dobj.namespace->dobj.name, \
+       fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
                                   (obj)->dobj.name)
 
 static void help(const char *progname);
 static void setup_connection(Archive *AH,
-                                const char *dumpencoding, const char *dumpsnapshot,
-                                char *use_role);
+                                                        const char *dumpencoding, const char *dumpsnapshot,
+                                                        char *use_role);
 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
 static void expand_schema_name_patterns(Archive *fout,
-                                                       SimpleStringList *patterns,
-                                                       SimpleOidList *oids,
-                                                       bool strict_names);
+                                                                               SimpleStringList *patterns,
+                                                                               SimpleOidList *oids,
+                                                                               bool strict_names);
 static void expand_table_name_patterns(Archive *fout,
-                                                  SimpleStringList *patterns,
-                                                  SimpleOidList *oids,
-                                                  bool strict_names);
+                                                                          SimpleStringList *patterns,
+                                                                          SimpleOidList *oids,
+                                                                          bool strict_names);
 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
 static void dumpComment(Archive *fout, const char *type, const char *name,
-                       const char *namespace, const char *owner,
-                       CatalogId catalogId, int subid, DumpId dumpId);
-static int findComments(Archive *fout, Oid classoid, Oid objoid,
-                        CommentItem **items);
+                                               const char *namespace, const char *owner,
+                                               CatalogId catalogId, int subid, DumpId dumpId);
+static int     findComments(Archive *fout, Oid classoid, Oid objoid,
+                                                CommentItem **items);
 static int     collectComments(Archive *fout, CommentItem **items);
 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);
+                                                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, DumpableObject *dobj);
 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
@@ -214,41 +222,41 @@ static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
 static void dumpUserMappings(Archive *fout,
-                                const char *servername, const char *namespace,
-                                const char *owner, CatalogId catalogId, DumpId dumpId);
+                                                        const char *servername, const char *namespace,
+                                                        const char *owner, CatalogId catalogId, DumpId dumpId);
 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
 
 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
-               const char *type, const char *name, const char *subname,
-               const char *nspname, const char *owner,
-               const char *acls, const char *racls,
-               const char *initacls, const char *initracls);
+                                       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);
 
 static void getDependencies(Archive *fout);
 static void BuildArchiveDependencies(Archive *fout);
 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
-                                                DumpId **dependencies, int *nDeps, int *allocDeps);
+                                                                        DumpId **dependencies, int *nDeps, int *allocDeps);
 
 static DumpableObject *createBoundaryObjects(void);
 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
-                                               DumpableObject *boundaryObjs);
+                                                                       DumpableObject *boundaryObjs);
 
 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
-static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind);
-static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids);
+static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
+static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
 static void buildMatViewRefreshDependencies(Archive *fout);
 static void getTableDataFKConstraints(void);
 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
-                                                 bool is_agg);
+                                                                          bool is_agg);
 static char *format_function_arguments_old(Archive *fout,
-                                                         FuncInfo *finfo, int nallargs,
-                                                         char **allargtypes,
-                                                         char **argmodes,
-                                                         char **argnames);
+                                                                                  FuncInfo *finfo, int nallargs,
+                                                                                  char **allargtypes,
+                                                                                  char **argmodes,
+                                                                                  char **argnames);
 static char *format_function_signature(Archive *fout,
-                                                 FuncInfo *finfo, bool honor_quotes);
+                                                                          FuncInfo *finfo, bool honor_quotes);
 static char *convertRegProcReference(Archive *fout,
-                                               const char *proc);
+                                                                        const char *proc);
 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
 static char *convertTSFunction(Archive *fout, Oid funcOid);
 static Oid     findLastBuiltinOid_V71(Archive *fout);
@@ -262,29 +270,29 @@ static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
 static void dumpDatabase(Archive *AH);
 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
-                                  const char *dbname, Oid dboid);
+                                                          const char *dbname, Oid dboid);
 static void dumpEncoding(Archive *AH);
 static void dumpStdStrings(Archive *AH);
 static void dumpSearchPath(Archive *AH);
 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
-                                                                                PQExpBuffer upgrade_buffer,
-                                                                                Oid pg_type_oid,
-                                                                                bool force_array_type);
+                                                                                                        PQExpBuffer upgrade_buffer,
+                                                                                                        Oid pg_type_oid,
+                                                                                                        bool force_array_type);
 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
-                                                                               PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
+                                                                                                       PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
 static void binary_upgrade_set_pg_class_oids(Archive *fout,
-                                                                PQExpBuffer upgrade_buffer,
-                                                                Oid pg_class_oid, bool is_index);
+                                                                                        PQExpBuffer upgrade_buffer,
+                                                                                        Oid pg_class_oid, bool is_index);
 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
-                                                               DumpableObject *dobj,
-                                                               const char *objtype,
-                                                               const char *objname,
-                                                               const char *objnamespace);
+                                                                                       DumpableObject *dobj,
+                                                                                       const char *objtype,
+                                                                                       const char *objname,
+                                                                                       const char *objnamespace);
 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
 static bool nonemptyReloptions(const char *reloptions);
 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
-                                               const char *prefix, Archive *fout);
+                                                                       const char *prefix, Archive *fout);
 static char *get_synchronized_snapshot(Archive *fout);
 static void setupDumpWorker(Archive *AHX);
 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
@@ -303,11 +311,14 @@ main(int argc, char **argv)
        DumpableObject *boundaryObjs;
        int                     i;
        int                     optindex;
+       char       *endptr;
        RestoreOptions *ropt;
        Archive    *fout;                       /* the script file */
+       bool            g_verbose = false;
        const char *dumpencoding = NULL;
        const char *dumpsnapshot = NULL;
        char       *use_role = NULL;
+       long            rowsPerInsert;
        int                     numWorkers = 1;
        trivalue        prompt_password = TRI_DEFAULT;
        int                     compressLevel = -1;
@@ -329,7 +340,6 @@ main(int argc, char **argv)
                {"host", required_argument, NULL, 'h'},
                {"jobs", 1, NULL, 'j'},
                {"no-reconnect", no_argument, NULL, 'R'},
-               {"oids", no_argument, NULL, 'o'},
                {"no-owner", no_argument, NULL, 'O'},
                {"port", required_argument, NULL, 'p'},
                {"schema", required_argument, NULL, 'n'},
@@ -359,8 +369,9 @@ main(int argc, char **argv)
                {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
                {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
                {"exclude-table-data", required_argument, NULL, 4},
+               {"extra-float-digits", required_argument, NULL, 8},
                {"if-exists", no_argument, &dopt.if_exists, 1},
-               {"inserts", no_argument, &dopt.dump_inserts, 1},
+               {"inserts", no_argument, NULL, 9},
                {"lock-wait-timeout", required_argument, NULL, 2},
                {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
                {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
@@ -379,10 +390,13 @@ main(int argc, char **argv)
                {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
                {"no-sync", no_argument, NULL, 7},
                {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
+               {"rows-per-insert", required_argument, NULL, 10},
 
                {NULL, 0, NULL, 0}
        };
 
+       pg_logging_init(argv[0]);
+       pg_logging_set_level(PG_LOG_WARNING);
        set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
 
        /*
@@ -391,8 +405,6 @@ main(int argc, char **argv)
         */
        init_parallel_dump_utils();
 
-       g_verbose = false;
-
        strcpy(g_comment_start, "-- ");
        g_comment_end[0] = '\0';
        strcpy(g_opaque_type, "opaque");
@@ -415,7 +427,7 @@ main(int argc, char **argv)
 
        InitDumpOptions(&dopt);
 
-       while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
+       while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
                                                        long_options, &optindex)) != -1)
        {
                switch (c)
@@ -473,10 +485,6 @@ main(int argc, char **argv)
                                simple_string_list_append(&schema_exclude_patterns, optarg);
                                break;
 
-                       case 'o':                       /* Dump oids */
-                               dopt.oids = true;
-                               break;
-
                        case 'O':                       /* Don't reconnect to match owner */
                                dopt.outputNoOwner = 1;
                                break;
@@ -512,6 +520,7 @@ main(int argc, char **argv)
 
                        case 'v':                       /* verbose */
                                g_verbose = true;
+                               pg_logging_set_level(PG_LOG_INFO);
                                break;
 
                        case 'w':
@@ -530,7 +539,7 @@ main(int argc, char **argv)
                                compressLevel = atoi(optarg);
                                if (compressLevel < 0 || compressLevel > 9)
                                {
-                                       write_msg(NULL, "compression level must be in range 0..9\n");
+                                       pg_log_error("compression level must be in range 0..9");
                                        exit_nicely(1);
                                }
                                break;
@@ -563,6 +572,41 @@ main(int argc, char **argv)
                                dosync = false;
                                break;
 
+                       case 8:
+                               have_extra_float_digits = true;
+                               extra_float_digits = atoi(optarg);
+                               if (extra_float_digits < -15 || extra_float_digits > 3)
+                               {
+                                       pg_log_error("extra_float_digits must be in range -15..3");
+                                       exit_nicely(1);
+                               }
+                               break;
+
+                       case 9:                         /* inserts */
+
+                               /*
+                                * dump_inserts also stores --rows-per-insert, careful not to
+                                * overwrite that.
+                                */
+                               if (dopt.dump_inserts == 0)
+                                       dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
+                               break;
+
+                       case 10:                        /* rows per insert */
+                               errno = 0;
+                               rowsPerInsert = strtol(optarg, &endptr, 10);
+
+                               if (endptr == optarg || *endptr != '\0' ||
+                                       rowsPerInsert <= 0 || rowsPerInsert > INT_MAX ||
+                                       errno == ERANGE)
+                               {
+                                       pg_log_error("rows-per-insert must be in range %d..%d",
+                                                                1, INT_MAX);
+                                       exit_nicely(1);
+                               }
+                               dopt.dump_inserts = (int) rowsPerInsert;
+                               break;
+
                        default:
                                fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
                                exit_nicely(1);
@@ -579,16 +623,16 @@ main(int argc, char **argv)
        /* Complain if any arguments remain */
        if (optind < argc)
        {
-               fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-                               progname, argv[optind]);
+               pg_log_error("too many command-line arguments (first is \"%s\")",
+                                        argv[optind]);
                fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
                                progname);
                exit_nicely(1);
        }
 
        /* --column-inserts implies --inserts */
-       if (dopt.column_inserts)
-               dopt.dump_inserts = 1;
+       if (dopt.column_inserts && dopt.dump_inserts == 0)
+               dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
 
        /*
         * Binary upgrade mode implies dumping sequence data even in schema-only
@@ -600,28 +644,25 @@ main(int argc, char **argv)
 
        if (dopt.dataOnly && dopt.schemaOnly)
        {
-               write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
+               pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together");
                exit_nicely(1);
        }
 
        if (dopt.dataOnly && dopt.outputClean)
        {
-               write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
-               exit_nicely(1);
-       }
-
-       if (dopt.dump_inserts && dopt.oids)
-       {
-               write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
-               write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
+               pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
                exit_nicely(1);
        }
 
        if (dopt.if_exists && !dopt.outputClean)
-               exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
+               fatal("option --if-exists requires option -c/--clean");
 
-       if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts))
-               exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts or --column-inserts\n");
+       /*
+        * --inserts are already implied above if --column-inserts or
+        * --rows-per-insert were specified.
+        */
+       if (dopt.do_nothing && dopt.dump_inserts == 0)
+               fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
 
        /* Identify archive format to emit */
        archiveFormat = parseArchiveFormat(format, &archiveMode);
@@ -643,8 +684,7 @@ main(int argc, char **argv)
 
 #ifndef HAVE_LIBZ
        if (compressLevel != 0)
-               write_msg(NULL, "WARNING: requested compression not available in this "
-                                 "installation -- archive will be uncompressed\n");
+               pg_log_warning("requested compression not available in this installation -- archive will be uncompressed");
        compressLevel = 0;
 #endif
 
@@ -665,11 +705,11 @@ main(int argc, char **argv)
                || numWorkers > MAXIMUM_WAIT_OBJECTS
 #endif
                )
-               exit_horribly(NULL, "invalid number of parallel jobs\n");
+               fatal("invalid number of parallel jobs");
 
        /* Parallel backup only in the directory archive format so far */
        if (archiveFormat != archDirectory && numWorkers > 1)
-               exit_horribly(NULL, "parallel backup only supported by the directory format\n");
+               fatal("parallel backup only supported by the directory format");
 
        /* Open the output file */
        fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
@@ -684,6 +724,7 @@ main(int argc, char **argv)
        /* Let the archiver know how noisy to be */
        fout->verbose = g_verbose;
 
+
        /*
         * We allow the server to be back to 8.0, and up to any minor release of
         * our own major version.  (See also version check in pg_dumpall.c.)
@@ -723,15 +764,13 @@ main(int argc, char **argv)
        /* check the version for the synchronized snapshots feature */
        if (numWorkers > 1 && fout->remoteVersion < 90200
                && !dopt.no_synchronized_snapshots)
-               exit_horribly(NULL,
-                                         "Synchronized snapshots are not supported by this server version.\n"
-                                         "Run with --no-synchronized-snapshots instead if you do not need\n"
-                                         "synchronized snapshots.\n");
+               fatal("Synchronized snapshots are not supported by this server version.\n"
+                         "Run with --no-synchronized-snapshots instead if you do not need\n"
+                         "synchronized snapshots.");
 
        /* check the version when a snapshot is explicitly specified by user */
        if (dumpsnapshot && fout->remoteVersion < 90200)
-               exit_horribly(NULL,
-                                         "Exported snapshots are not supported by this server version.\n");
+               fatal("Exported snapshots are not supported by this server version.");
 
        /*
         * Find the last built-in OID, if needed (prior to 8.1)
@@ -743,8 +782,7 @@ main(int argc, char **argv)
        else
                g_last_builtin_oid = FirstNormalObjectId - 1;
 
-       if (g_verbose)
-               write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
+       pg_log_info("last built-in OID is %u", g_last_builtin_oid);
 
        /* Expand schema selection patterns into OID lists */
        if (schema_include_patterns.head != NULL)
@@ -753,7 +791,7 @@ main(int argc, char **argv)
                                                                        &schema_include_oids,
                                                                        strict_names);
                if (schema_include_oids.head == NULL)
-                       exit_horribly(NULL, "no matching schemas were found\n");
+                       fatal("no matching schemas were found");
        }
        expand_schema_name_patterns(fout, &schema_exclude_patterns,
                                                                &schema_exclude_oids,
@@ -767,7 +805,7 @@ main(int argc, char **argv)
                                                                   &table_include_oids,
                                                                   strict_names);
                if (table_include_oids.head == NULL)
-                       exit_horribly(NULL, "no matching tables were found\n");
+                       fatal("no matching tables were found");
        }
        expand_table_name_patterns(fout, &table_exclude_patterns,
                                                           &table_exclude_oids,
@@ -802,14 +840,14 @@ main(int argc, char **argv)
 
        if (!dopt.schemaOnly)
        {
-               getTableData(&dopt, tblinfo, numTables, dopt.oids, 0);
+               getTableData(&dopt, tblinfo, numTables, 0);
                buildMatViewRefreshDependencies(fout);
                if (dopt.dataOnly)
                        getTableDataFKConstraints();
        }
 
        if (dopt.schemaOnly && dopt.sequence_data)
-               getTableData(&dopt, tblinfo, numTables, dopt.oids, RELKIND_SEQUENCE);
+               getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
 
        /*
         * In binary-upgrade mode, we do not have to worry about the actual blob
@@ -847,10 +885,6 @@ main(int argc, char **argv)
         */
        sortDumpableObjectsByTypeName(dobjs, numObjs);
 
-       /* If we do a parallel dump, we want the largest tables to go first */
-       if (archiveFormat == archDirectory && numWorkers > 1)
-               sortDataAndIndexObjectsBySize(dobjs, numObjs);
-
        sortDumpableObjects(dobjs, numObjs,
                                                boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
 
@@ -968,7 +1002,6 @@ help(const char *progname)
        printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
        printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
        printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
-       printf(_("  -o, --oids                   include OIDs in dump\n"));
        printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
                         "                               plain-text format\n"));
        printf(_("  -s, --schema-only            dump only the schema, no data\n"));
@@ -983,6 +1016,7 @@ help(const char *progname)
        printf(_("  --enable-row-security        enable row security (dump only content user has\n"
                         "                               access to)\n"));
        printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
+       printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
        printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
        printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
        printf(_("  --load-via-partition-root    load partitions via the root table\n"));
@@ -995,6 +1029,7 @@ help(const char *progname)
        printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
        printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
        printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
+       printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
        printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
        printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
        printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
@@ -1015,7 +1050,7 @@ help(const char *progname)
 
        printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
                         "variable value is used.\n\n"));
-       printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
+       printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
 }
 
 static void
@@ -1034,8 +1069,8 @@ setup_connection(Archive *AH, const char *dumpencoding,
        if (dumpencoding)
        {
                if (PQsetClientEncoding(conn, dumpencoding) < 0)
-                       exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
-                                                 dumpencoding);
+                       fatal("invalid client encoding \"%s\" specified",
+                                 dumpencoding);
        }
 
        /*
@@ -1077,10 +1112,20 @@ setup_connection(Archive *AH, const char *dumpencoding,
                ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
 
        /*
-        * Set extra_float_digits so that we can dump float data exactly (given
-        * correctly implemented float I/O code, anyway)
+        * Use an explicitly specified extra_float_digits if it has been provided.
+        * Otherwise, set extra_float_digits so that we can dump float data
+        * exactly (given correctly implemented float I/O code, anyway).
         */
-       if (AH->remoteVersion >= 90000)
+       if (have_extra_float_digits)
+       {
+               PQExpBuffer q = createPQExpBuffer();
+
+               appendPQExpBuffer(q, "SET extra_float_digits TO %d",
+                                                 extra_float_digits);
+               ExecuteSqlStatement(AH, q->data);
+               destroyPQExpBuffer(q);
+       }
+       else if (AH->remoteVersion >= 90000)
                ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
        else
                ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
@@ -1160,7 +1205,7 @@ setup_connection(Archive *AH, const char *dumpencoding,
        {
                PQExpBuffer query = createPQExpBuffer();
 
-               appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
+               appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
                appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
                ExecuteSqlStatement(AH, query->data);
                destroyPQExpBuffer(query);
@@ -1170,10 +1215,9 @@ setup_connection(Archive *AH, const char *dumpencoding,
                         !dopt->no_synchronized_snapshots)
        {
                if (AH->isStandby && AH->remoteVersion < 100000)
-                       exit_horribly(NULL,
-                                                 "Synchronized snapshots on standby servers are not supported by this server version.\n"
-                                                 "Run with --no-synchronized-snapshots instead if you do not need\n"
-                                                 "synchronized snapshots.\n");
+                       fatal("Synchronized snapshots on standby servers are not supported by this server version.\n"
+                                 "Run with --no-synchronized-snapshots instead if you do not need\n"
+                                 "synchronized snapshots.");
 
 
                AH->sync_snapshot_id = get_synchronized_snapshot(AH);
@@ -1240,7 +1284,7 @@ parseArchiveFormat(const char *format, ArchiveMode *mode)
        else if (pg_strcasecmp(format, "tar") == 0)
                archiveFormat = archTar;
        else
-               exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
+               fatal("invalid output format \"%s\" specified", format);
        return archiveFormat;
 }
 
@@ -1271,14 +1315,14 @@ expand_schema_name_patterns(Archive *fout,
 
        for (cell = patterns->head; cell; cell = cell->next)
        {
-               appendPQExpBuffer(query,
-                                                 "SELECT oid FROM pg_catalog.pg_namespace n\n");
+               appendPQExpBufferStr(query,
+                                                        "SELECT oid FROM pg_catalog.pg_namespace n\n");
                processSQLNamePattern(GetConnection(fout), query, cell->val, false,
                                                          false, NULL, "n.nspname", NULL, NULL);
 
                res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
                if (strict_names && PQntuples(res) == 0)
-                       exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
+                       fatal("no matching schemas were found for pattern \"%s\"", cell->val);
 
                for (i = 0; i < PQntuples(res); i++)
                {
@@ -1294,7 +1338,8 @@ expand_schema_name_patterns(Archive *fout,
 
 /*
  * Find the OIDs of all tables matching the given list of patterns,
- * and append them to the given OID list.
+ * and append them to the given OID list. See also expand_dbname_patterns()
+ * in pg_dumpall.c
  */
 static void
 expand_table_name_patterns(Archive *fout,
@@ -1342,7 +1387,7 @@ expand_table_name_patterns(Archive *fout,
                PQclear(ExecuteSqlQueryForSingleRow(fout,
                                                                                        ALWAYS_SECURE_SEARCH_PATH_SQL));
                if (strict_names && PQntuples(res) == 0)
-                       exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
+                       fatal("no matching tables were found for pattern \"%s\"", cell->val);
 
                for (i = 0; i < PQntuples(res); i++)
                {
@@ -1743,8 +1788,6 @@ dumpTableData_copy(Archive *fout, void *dcontext)
        TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
        TableInfo  *tbinfo = tdinfo->tdtable;
        const char *classname = tbinfo->dobj.name;
-       const bool      hasoids = tbinfo->hasoids;
-       const bool      oids = tdinfo->oids;
        PQExpBuffer q = createPQExpBuffer();
 
        /*
@@ -1758,9 +1801,8 @@ dumpTableData_copy(Archive *fout, void *dcontext)
        char       *copybuf;
        const char *column_list;
 
-       if (g_verbose)
-               write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
-                                 tbinfo->dobj.namespace->dobj.name, classname);
+       pg_log_info("dumping contents of table \"%s.%s\"",
+                               tbinfo->dobj.namespace->dobj.name, classname);
 
        /*
         * Specify the column list explicitly so that we have no possibility of
@@ -1770,13 +1812,7 @@ dumpTableData_copy(Archive *fout, void *dcontext)
         */
        column_list = fmtCopyColumnList(tbinfo, clistBuf);
 
-       if (oids && hasoids)
-       {
-               appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
-                                                 fmtQualifiedDumpable(tbinfo),
-                                                 column_list);
-       }
-       else if (tdinfo->filtercond)
+       if (tdinfo->filtercond)
        {
                /* Note: this syntax is only supported in 8.2 and up */
                appendPQExpBufferStr(q, "COPY (SELECT ");
@@ -1866,9 +1902,9 @@ dumpTableData_copy(Archive *fout, void *dcontext)
        if (ret == -2)
        {
                /* copy data transfer failed */
-               write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
-               write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
-               write_msg(NULL, "The command was: %s\n", q->data);
+               pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
+               pg_log_error("Error message from server: %s", PQerrorMessage(conn));
+               pg_log_error("The command was: %s", q->data);
                exit_nicely(1);
        }
 
@@ -1876,17 +1912,17 @@ dumpTableData_copy(Archive *fout, void *dcontext)
        res = PQgetResult(conn);
        if (PQresultStatus(res) != PGRES_COMMAND_OK)
        {
-               write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
-               write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
-               write_msg(NULL, "The command was: %s\n", q->data);
+               pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
+               pg_log_error("Error message from server: %s", PQerrorMessage(conn));
+               pg_log_error("The command was: %s", q->data);
                exit_nicely(1);
        }
        PQclear(res);
 
        /* Do this to ensure we've pumped libpq back to idle state */
        if (PQgetResult(conn) != NULL)
-               write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
-                                 classname);
+               pg_log_warning("unexpected extra results during COPY of table \"%s\"",
+                                          classname);
 
        destroyPQExpBuffer(q);
        return 1;
@@ -1909,9 +1945,9 @@ dumpTableData_insert(Archive *fout, void *dcontext)
        PQExpBuffer q = createPQExpBuffer();
        PQExpBuffer insertStmt = NULL;
        PGresult   *res;
-       int                     tuple;
        int                     nfields;
-       int                     field;
+       int                     rows_per_statement = dopt->dump_inserts;
+       int                     rows_this_statement = 0;
 
        appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
                                          "SELECT * FROM ONLY %s",
@@ -1926,72 +1962,96 @@ dumpTableData_insert(Archive *fout, void *dcontext)
                res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
                                                          PGRES_TUPLES_OK);
                nfields = PQnfields(res);
-               for (tuple = 0; tuple < PQntuples(res); tuple++)
+
+               /*
+                * First time through, we build as much of the INSERT statement as
+                * possible in "insertStmt", which we can then just print for each
+                * statement. If the table happens to have zero columns then this will
+                * be a complete statement, otherwise it will end in "VALUES" and be
+                * ready to have the row's column values printed.
+                */
+               if (insertStmt == NULL)
                {
-                       /*
-                        * First time through, we build as much of the INSERT statement as
-                        * possible in "insertStmt", which we can then just print for each
-                        * line. If the table happens to have zero columns then this will
-                        * be a complete statement, otherwise it will end in "VALUES(" and
-                        * be ready to have the row's column values appended.
-                        */
-                       if (insertStmt == NULL)
-                       {
-                               TableInfo  *targettab;
+                       TableInfo  *targettab;
 
-                               insertStmt = createPQExpBuffer();
+                       insertStmt = createPQExpBuffer();
 
-                               /*
-                                * When load-via-partition-root is set, get the root table
-                                * name for the partition table, so that we can reload data
-                                * through the root table.
-                                */
-                               if (dopt->load_via_partition_root && tbinfo->ispartition)
-                                       targettab = getRootTableInfo(tbinfo);
-                               else
-                                       targettab = tbinfo;
+                       /*
+                        * When load-via-partition-root is set, get the root table name
+                        * for the partition table, so that we can reload data through the
+                        * root table.
+                        */
+                       if (dopt->load_via_partition_root && tbinfo->ispartition)
+                               targettab = getRootTableInfo(tbinfo);
+                       else
+                               targettab = tbinfo;
 
-                               appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
-                                                                 fmtQualifiedDumpable(targettab));
+                       appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
+                                                         fmtQualifiedDumpable(targettab));
 
-                               /* corner case for zero-column table */
-                               if (nfields == 0)
-                               {
-                                       appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
-                               }
-                               else
+                       /* corner case for zero-column table */
+                       if (nfields == 0)
+                       {
+                               appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
+                       }
+                       else
+                       {
+                               /* append the list of column names if required */
+                               if (dopt->column_inserts)
                                {
-                                       /* append the list of column names if required */
-                                       if (dopt->column_inserts)
+                                       appendPQExpBufferChar(insertStmt, '(');
+                                       for (int field = 0; field < nfields; field++)
                                        {
-                                               appendPQExpBufferChar(insertStmt, '(');
-                                               for (field = 0; field < nfields; field++)
-                                               {
-                                                       if (field > 0)
-                                                               appendPQExpBufferStr(insertStmt, ", ");
-                                                       appendPQExpBufferStr(insertStmt,
-                                                                                                fmtId(PQfname(res, field)));
-                                               }
-                                               appendPQExpBufferStr(insertStmt, ") ");
+                                               if (field > 0)
+                                                       appendPQExpBufferStr(insertStmt, ", ");
+                                               appendPQExpBufferStr(insertStmt,
+                                                                                        fmtId(PQfname(res, field)));
                                        }
+                                       appendPQExpBufferStr(insertStmt, ") ");
+                               }
 
-                                       if (tbinfo->needs_override)
-                                               appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
+                               if (tbinfo->needs_override)
+                                       appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
 
-                                       appendPQExpBufferStr(insertStmt, "VALUES (");
-                               }
+                               appendPQExpBufferStr(insertStmt, "VALUES");
                        }
+               }
 
-                       archputs(insertStmt->data, fout);
+               for (int tuple = 0; tuple < PQntuples(res); tuple++)
+               {
+                       /* Write the INSERT if not in the middle of a multi-row INSERT. */
+                       if (rows_this_statement == 0)
+                               archputs(insertStmt->data, fout);
 
-                       /* if it is zero-column table then we're done */
+                       /*
+                        * If it is zero-column table then we've already written the
+                        * complete statement, which will mean we've disobeyed
+                        * --rows-per-insert when it's set greater than 1.  We do support
+                        * a way to make this multi-row with: SELECT UNION ALL SELECT
+                        * UNION ALL ... but that's non-standard so we should avoid it
+                        * given that using INSERTs is mostly only ever needed for
+                        * cross-database exports.
+                        */
                        if (nfields == 0)
                                continue;
 
-                       for (field = 0; field < nfields; field++)
+                       /* Emit a row heading */
+                       if (rows_per_statement == 1)
+                               archputs(" (", fout);
+                       else if (rows_this_statement > 0)
+                               archputs(",\n\t(", fout);
+                       else
+                               archputs("\n\t(", fout);
+
+                       for (int field = 0; field < nfields; field++)
                        {
                                if (field > 0)
                                        archputs(", ", fout);
+                               if (tbinfo->attgenerated[field])
+                               {
+                                       archputs("DEFAULT", fout);
+                                       continue;
+                               }
                                if (PQgetisnull(res, tuple, field))
                                {
                                        archputs("NULL", fout);
@@ -2053,10 +2113,19 @@ dumpTableData_insert(Archive *fout, void *dcontext)
                                }
                        }
 
-                       if (!dopt->do_nothing)
-                               archputs(");\n", fout);
-                       else
-                               archputs(") ON CONFLICT DO NOTHING;\n", fout);
+                       /* Terminate the row ... */
+                       archputs(")", fout);
+
+                       /* ... and the statement, if the target no. of rows is reached */
+                       if (++rows_this_statement >= rows_per_statement)
+                       {
+                               if (dopt->do_nothing)
+                                       archputs(" ON CONFLICT DO NOTHING;\n", fout);
+                               else
+                                       archputs(";\n", fout);
+                               /* Reset the row counter */
+                               rows_this_statement = 0;
+                       }
                }
 
                if (PQntuples(res) <= 0)
@@ -2067,6 +2136,15 @@ dumpTableData_insert(Archive *fout, void *dcontext)
                PQclear(res);
        }
 
+       /* Terminate any statements that didn't make the row count. */
+       if (rows_this_statement > 0)
+       {
+               if (dopt->do_nothing)
+                       archputs(" ON CONFLICT DO NOTHING;\n", fout);
+               else
+                       archputs(";\n", fout);
+       }
+
        archputs("\n\n", fout);
 
        ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
@@ -2140,9 +2218,8 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
                /* must use 2 steps here 'cause fmtId is nonreentrant */
                appendPQExpBuffer(copyBuf, "COPY %s ",
                                                  copyFrom);
-               appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
-                                                 fmtCopyColumnList(tbinfo, clistBuf),
-                                                 (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
+               appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
+                                                 fmtCopyColumnList(tbinfo, clistBuf));
                copyStmt = copyBuf->data;
        }
        else
@@ -2158,13 +2235,32 @@ dumpTableData(Archive *fout, TableDataInfo *tdinfo)
         * See comments for BuildArchiveDependencies.
         */
        if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
-               ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
-                                        tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
-                                        NULL, tbinfo->rolname,
-                                        false, "TABLE DATA", SECTION_DATA,
-                                        "", "", copyStmt,
-                                        &(tbinfo->dobj.dumpId), 1,
-                                        dumpFn, tdinfo);
+       {
+               TocEntry   *te;
+
+               te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
+                                                 ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
+                                                                          .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                          .owner = tbinfo->rolname,
+                                                                          .description = "TABLE DATA",
+                                                                          .section = SECTION_DATA,
+                                                                          .copyStmt = copyStmt,
+                                                                          .deps = &(tbinfo->dobj.dumpId),
+                                                                          .nDeps = 1,
+                                                                          .dumpFn = dumpFn,
+                                                                          .dumpArg = 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.
+                * 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;
+       }
 
        destroyPQExpBuffer(copyBuf);
        destroyPQExpBuffer(clistBuf);
@@ -2196,20 +2292,14 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
                ArchiveEntry(fout,
                                         tdinfo->dobj.catId,    /* catalog ID */
                                         tdinfo->dobj.dumpId,   /* dump ID */
-                                        tbinfo->dobj.name, /* Name */
-                                        tbinfo->dobj.namespace->dobj.name, /* Namespace */
-                                        NULL,          /* Tablespace */
-                                        tbinfo->rolname,       /* Owner */
-                                        false,         /* with oids */
-                                        "MATERIALIZED VIEW DATA",      /* Desc */
-                                        SECTION_POST_DATA, /* Section */
-                                        q->data,       /* Create */
-                                        "",            /* Del */
-                                        NULL,          /* Copy */
-                                        tdinfo->dobj.dependencies, /* Deps */
-                                        tdinfo->dobj.nDeps,    /* # Deps */
-                                        NULL,          /* Dumper */
-                                        NULL);         /* Dumper Arg */
+                                        ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "MATERIALIZED VIEW DATA",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .deps = tdinfo->dobj.dependencies,
+                                                                 .nDeps = tdinfo->dobj.nDeps));
 
        destroyPQExpBuffer(q);
 }
@@ -2219,7 +2309,7 @@ refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
  *       set up dumpable objects representing the contents of tables
  */
 static void
-getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind)
+getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
 {
        int                     i;
 
@@ -2227,7 +2317,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, ch
        {
                if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
                        (!relkind || tblinfo[i].relkind == relkind))
-                       makeTableDataInfo(dopt, &(tblinfo[i]), oids);
+                       makeTableDataInfo(dopt, &(tblinfo[i]));
        }
 }
 
@@ -2238,7 +2328,7 @@ getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, ch
  * table data; the "dump" flag in such objects isn't used.
  */
 static void
-makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
+makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
 {
        TableDataInfo *tdinfo;
 
@@ -2289,7 +2379,6 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
        tdinfo->dobj.name = tbinfo->dobj.name;
        tdinfo->dobj.namespace = tbinfo->dobj.namespace;
        tdinfo->tdtable = tbinfo;
-       tdinfo->oids = oids;
        tdinfo->filtercond = NULL;      /* might get set later */
        addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
 
@@ -2574,23 +2663,43 @@ dumpDatabase(Archive *fout)
                                minmxid;
        char       *qdatname;
 
-       if (g_verbose)
-               write_msg(NULL, "saving database definition\n");
+       pg_log_info("saving database definition");
 
-       /* Fetch the database-level properties for this database */
+       /*
+        * 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)
        {
                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 acl::text COLLATE \"C\") FROM ( "
-                                                 "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
-                                                 "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
+                                                 "(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 acl::text COLLATE \"C\") FROM ( "
-                                                 "  SELECT unnest(acldefault('d',datdba)) AS acl "
-                                                 "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
+                                                 "(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, "
                                                  "datistemplate, datconnlimit, "
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
@@ -2703,15 +2812,23 @@ dumpDatabase(Archive *fout)
                appendPQExpBufferStr(creaQry, " ENCODING = ");
                appendStringLiteralAH(creaQry, encoding, fout);
        }
-       if (strlen(collate) > 0)
+       if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
        {
-               appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
+               appendPQExpBufferStr(creaQry, " LOCALE = ");
                appendStringLiteralAH(creaQry, collate, fout);
        }
-       if (strlen(ctype) > 0)
+       else
        {
-               appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
-               appendStringLiteralAH(creaQry, ctype, fout);
+               if (strlen(collate) > 0)
+               {
+                       appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
+                       appendStringLiteralAH(creaQry, collate, fout);
+               }
+               if (strlen(ctype) > 0)
+               {
+                       appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
+                       appendStringLiteralAH(creaQry, ctype, fout);
+               }
        }
 
        /*
@@ -2736,20 +2853,12 @@ dumpDatabase(Archive *fout)
        ArchiveEntry(fout,
                                 dbCatId,               /* catalog ID */
                                 dbDumpId,              /* dump ID */
-                                datname,               /* Name */
-                                NULL,                  /* Namespace */
-                                NULL,                  /* Tablespace */
-                                dba,                   /* Owner */
-                                false,                 /* with oids */
-                                "DATABASE",    /* Desc */
-                                SECTION_PRE_DATA,      /* Section */
-                                creaQry->data, /* Create */
-                                delQry->data,  /* Del */
-                                NULL,                  /* Copy */
-                                NULL,                  /* Deps */
-                                0,                             /* # Deps */
-                                NULL,                  /* Dumper */
-                                NULL);                 /* Dumper Arg */
+                                ARCHIVE_OPTS(.tag = datname,
+                                                         .owner = dba,
+                                                         .description = "DATABASE",
+                                                         .section = SECTION_PRE_DATA,
+                                                         .createStmt = creaQry->data,
+                                                         .dropStmt = delQry->data));
 
        /* Compute correct tag for archive entry */
        appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
@@ -2777,11 +2886,13 @@ dumpDatabase(Archive *fout)
                        appendPQExpBufferStr(dbQry, ";\n");
 
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                                labelq->data, NULL, NULL, dba,
-                                                false, "COMMENT", SECTION_NONE,
-                                                dbQry->data, "", NULL,
-                                                &(dbDumpId), 1,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = labelq->data,
+                                                                         .owner = dba,
+                                                                         .description = "COMMENT",
+                                                                         .section = SECTION_NONE,
+                                                                         .createStmt = dbQry->data,
+                                                                         .deps = &dbDumpId,
+                                                                         .nDeps = 1));
                }
        }
        else
@@ -2804,11 +2915,13 @@ dumpDatabase(Archive *fout)
                emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
                if (seclabelQry->len > 0)
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                                labelq->data, NULL, NULL, dba,
-                                                false, "SECURITY LABEL", SECTION_NONE,
-                                                seclabelQry->data, "", NULL,
-                                                &(dbDumpId), 1,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = labelq->data,
+                                                                         .owner = dba,
+                                                                         .description = "SECURITY LABEL",
+                                                                         .section = SECTION_NONE,
+                                                                         .createStmt = seclabelQry->data,
+                                                                         .deps = &dbDumpId,
+                                                                         .nDeps = 1));
                destroyPQExpBuffer(seclabelQry);
                PQclear(shres);
        }
@@ -2874,15 +2987,17 @@ dumpDatabase(Archive *fout)
 
        if (creaQry->len > 0)
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        datname, NULL, NULL, dba,
-                                        false, "DATABASE PROPERTIES", SECTION_PRE_DATA,
-                                        creaQry->data, delQry->data, NULL,
-                                        &(dbDumpId), 1,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = datname,
+                                                                 .owner = dba,
+                                                                 .description = "DATABASE PROPERTIES",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = creaQry->data,
+                                                                 .dropStmt = delQry->data,
+                                                                 .deps = &dbDumpId));
 
        /*
-        * pg_largeobject and pg_largeobject_metadata come from the old system
-        * intact, so set their relfrozenxids and relminmxids.
+        * pg_largeobject comes from the old system intact, so set its
+        * relfrozenxids and relminmxids.
         */
        if (dopt->binary_upgrade)
        {
@@ -2919,55 +3034,13 @@ dumpDatabase(Archive *fout)
                                                  atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
                                                  LargeObjectRelationId);
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        "pg_largeobject", NULL, NULL, "",
-                                        false, "pg_largeobject", SECTION_PRE_DATA,
-                                        loOutQry->data, "", NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = "pg_largeobject",
+                                                                 .description = "pg_largeobject",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = loOutQry->data));
 
                PQclear(lo_res);
 
-               /*
-                * pg_largeobject_metadata
-                */
-               if (fout->remoteVersion >= 90000)
-               {
-                       resetPQExpBuffer(loFrozenQry);
-                       resetPQExpBuffer(loOutQry);
-
-                       if (fout->remoteVersion >= 90300)
-                               appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
-                                                                 "FROM pg_catalog.pg_class\n"
-                                                                 "WHERE oid = %u;\n",
-                                                                 LargeObjectMetadataRelationId);
-                       else
-                               appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
-                                                                 "FROM pg_catalog.pg_class\n"
-                                                                 "WHERE oid = %u;\n",
-                                                                 LargeObjectMetadataRelationId);
-
-                       lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
-
-                       i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
-                       i_relminmxid = PQfnumber(lo_res, "relminmxid");
-
-                       appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
-                       appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
-                                                         "SET relfrozenxid = '%u', relminmxid = '%u'\n"
-                                                         "WHERE oid = %u;\n",
-                                                         atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
-                                                         atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
-                                                         LargeObjectMetadataRelationId);
-                       ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                                "pg_largeobject_metadata", NULL, NULL, "",
-                                                false, "pg_largeobject_metadata", SECTION_PRE_DATA,
-                                                loOutQry->data, "", NULL,
-                                                NULL, 0,
-                                                NULL, NULL);
-
-                       PQclear(lo_res);
-               }
-
                destroyPQExpBuffer(loFrozenQry);
                destroyPQExpBuffer(loOutQry);
        }
@@ -3062,19 +3135,17 @@ dumpEncoding(Archive *AH)
        const char *encname = pg_encoding_to_char(AH->encoding);
        PQExpBuffer qry = createPQExpBuffer();
 
-       if (g_verbose)
-               write_msg(NULL, "saving encoding = %s\n", encname);
+       pg_log_info("saving encoding = %s", encname);
 
        appendPQExpBufferStr(qry, "SET client_encoding = ");
        appendStringLiteralAH(qry, encname, AH);
        appendPQExpBufferStr(qry, ";\n");
 
        ArchiveEntry(AH, nilCatalogId, createDumpId(),
-                                "ENCODING", NULL, NULL, "",
-                                false, "ENCODING", SECTION_PRE_DATA,
-                                qry->data, "", NULL,
-                                NULL, 0,
-                                NULL, NULL);
+                                ARCHIVE_OPTS(.tag = "ENCODING",
+                                                         .description = "ENCODING",
+                                                         .section = SECTION_PRE_DATA,
+                                                         .createStmt = qry->data));
 
        destroyPQExpBuffer(qry);
 }
@@ -3089,19 +3160,17 @@ dumpStdStrings(Archive *AH)
        const char *stdstrings = AH->std_strings ? "on" : "off";
        PQExpBuffer qry = createPQExpBuffer();
 
-       if (g_verbose)
-               write_msg(NULL, "saving standard_conforming_strings = %s\n",
-                                 stdstrings);
+       pg_log_info("saving standard_conforming_strings = %s",
+                               stdstrings);
 
        appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
                                          stdstrings);
 
        ArchiveEntry(AH, nilCatalogId, createDumpId(),
-                                "STDSTRINGS", NULL, NULL, "",
-                                false, "STDSTRINGS", SECTION_PRE_DATA,
-                                qry->data, "", NULL,
-                                NULL, 0,
-                                NULL, NULL);
+                                ARCHIVE_OPTS(.tag = "STDSTRINGS",
+                                                         .description = "STDSTRINGS",
+                                                         .section = SECTION_PRE_DATA,
+                                                         .createStmt = qry->data));
 
        destroyPQExpBuffer(qry);
 }
@@ -3130,7 +3199,7 @@ dumpSearchPath(Archive *AH)
                                                                          "SELECT pg_catalog.current_schemas(false)");
 
        if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
-               exit_horribly(NULL, "could not parse result of current_schemas()\n");
+               fatal("could not parse result of current_schemas()");
 
        /*
         * We use set_config(), not a simple "SET search_path" command, because
@@ -3149,15 +3218,13 @@ dumpSearchPath(Archive *AH)
        appendStringLiteralAH(qry, path->data, AH);
        appendPQExpBufferStr(qry, ", false);\n");
 
-       if (g_verbose)
-               write_msg(NULL, "saving search_path = %s\n", path->data);
+       pg_log_info("saving search_path = %s", path->data);
 
        ArchiveEntry(AH, nilCatalogId, createDumpId(),
-                                "SEARCHPATH", NULL, NULL, "",
-                                false, "SEARCHPATH", SECTION_PRE_DATA,
-                                qry->data, "", NULL,
-                                NULL, 0,
-                                NULL, NULL);
+                                ARCHIVE_OPTS(.tag = "SEARCHPATH",
+                                                         .description = "SEARCHPATH",
+                                                         .section = SECTION_PRE_DATA,
+                                                         .createStmt = qry->data));
 
        /* Also save it in AH->searchpath, in case we're doing plain text dump */
        AH->searchpath = pg_strdup(qry->data);
@@ -3191,9 +3258,7 @@ getBlobs(Archive *fout)
        int                     i_initlomacl;
        int                     i_initrlomacl;
 
-       /* Verbose message */
-       if (g_verbose)
-               write_msg(NULL, "reading large objects\n");
+       pg_log_info("reading large objects");
 
        /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
        if (fout->remoteVersion >= 90600)
@@ -3281,18 +3346,14 @@ getBlobs(Archive *fout)
                        binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
                /*
-                * In binary-upgrade mode for blobs, we do *not* dump out the data or
-                * the ACLs, should any exist.  The data and ACL (if any) will be
-                * copied by pg_upgrade, which simply copies the pg_largeobject and
-                * pg_largeobject_metadata tables.
-                *
-                * We *do* dump out the definition of the blob because we need that to
-                * make the restoration of the comments, and anything else, work since
-                * pg_upgrade copies the files behind pg_largeobject and
-                * pg_largeobject_metadata after the dump is restored.
+                * In binary-upgrade mode for blobs, we do *not* dump out the blob
+                * data, as it will be copied by pg_upgrade, which simply copies the
+                * pg_largeobject table. We *do* however dump out anything but the
+                * data, as pg_upgrade copies just pg_largeobject, but not
+                * pg_largeobject_metadata, after the dump is restored.
                 */
                if (dopt->binary_upgrade)
-                       binfo[i].dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL);
+                       binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
        }
 
        /*
@@ -3333,13 +3394,12 @@ dumpBlob(Archive *fout, BlobInfo *binfo)
 
        if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
-                                        binfo->dobj.name,
-                                        NULL, NULL,
-                                        binfo->rolname, false,
-                                        "BLOB", SECTION_PRE_DATA,
-                                        cquery->data, dquery->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = binfo->dobj.name,
+                                                                 .owner = binfo->rolname,
+                                                                 .description = "BLOB",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = cquery->data,
+                                                                 .dropStmt = dquery->data));
 
        /* Dump comment if any */
        if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -3380,17 +3440,20 @@ dumpBlobs(Archive *fout, void *arg)
        int                     i;
        int                     cnt;
 
-       if (g_verbose)
-               write_msg(NULL, "saving large objects\n");
+       pg_log_info("saving large objects");
 
        /*
         * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
         * the already-in-memory dumpable objects instead...
         */
        if (fout->remoteVersion >= 90000)
-               blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
+               blobQry =
+                       "DECLARE bloboid CURSOR FOR "
+                       "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
        else
-               blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
+               blobQry =
+                       "DECLARE bloboid CURSOR FOR "
+                       "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
 
        ExecuteSqlStatement(fout, blobQry);
 
@@ -3413,8 +3476,8 @@ dumpBlobs(Archive *fout, void *arg)
                        /* Open the BLOB */
                        loFd = lo_open(conn, blobOid, INV_READ);
                        if (loFd == -1)
-                               exit_horribly(NULL, "could not open large object %u: %s",
-                                                         blobOid, PQerrorMessage(conn));
+                               fatal("could not open large object %u: %s",
+                                         blobOid, PQerrorMessage(conn));
 
                        StartBlob(fout, blobOid);
 
@@ -3423,8 +3486,8 @@ dumpBlobs(Archive *fout, void *arg)
                        {
                                cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
                                if (cnt < 0)
-                                       exit_horribly(NULL, "error reading large object %u: %s",
-                                                                 blobOid, PQerrorMessage(conn));
+                                       fatal("error reading large object %u: %s",
+                                                 blobOid, PQerrorMessage(conn));
 
                                WriteData(fout, buf, cnt);
                        } while (cnt > 0);
@@ -3475,15 +3538,14 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
                if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
                        continue;
 
-               if (g_verbose)
-                       write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
-                                         tbinfo->dobj.namespace->dobj.name,
-                                         tbinfo->dobj.name);
+               pg_log_info("reading row security enabled for table \"%s.%s\"",
+                                       tbinfo->dobj.namespace->dobj.name,
+                                       tbinfo->dobj.name);
 
                /*
                 * Get row security enabled information for the table. We represent
-                * RLS enabled on a table by creating PolicyInfo object with an empty
-                * policy.
+                * RLS being enabled on a table by creating a PolicyInfo object with
+                * null polname.
                 */
                if (tbinfo->rowsec)
                {
@@ -3507,10 +3569,9 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
                        polinfo->polwithcheck = NULL;
                }
 
-               if (g_verbose)
-                       write_msg(NULL, "reading policies for table \"%s.%s\"\n",
-                                         tbinfo->dobj.namespace->dobj.name,
-                                         tbinfo->dobj.name);
+               pg_log_info("reading policies for table \"%s.%s\"",
+                                       tbinfo->dobj.namespace->dobj.name,
+                                       tbinfo->dobj.name);
 
                resetPQExpBuffer(query);
 
@@ -3624,18 +3685,23 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
                query = createPQExpBuffer();
 
                appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
-                                                 fmtQualifiedDumpable(polinfo));
+                                                 fmtQualifiedDumpable(tbinfo));
 
+               /*
+                * We must emit the ROW SECURITY object's dependency on its table
+                * explicitly, because it will not match anything in pg_depend (unlike
+                * the case for other PolicyInfo objects).
+                */
                if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
                        ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-                                                polinfo->dobj.name,
-                                                polinfo->dobj.namespace->dobj.name,
-                                                NULL,
-                                                tbinfo->rolname, false,
-                                                "ROW SECURITY", SECTION_POST_DATA,
-                                                query->data, "", NULL,
-                                                NULL, 0,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = polinfo->dobj.name,
+                                                                         .namespace = polinfo->dobj.namespace->dobj.name,
+                                                                         .owner = tbinfo->rolname,
+                                                                         .description = "ROW SECURITY",
+                                                                         .section = SECTION_POST_DATA,
+                                                                         .createStmt = query->data,
+                                                                         .deps = &(tbinfo->dobj.dumpId),
+                                                                         .nDeps = 1));
 
                destroyPQExpBuffer(query);
                return;
@@ -3653,8 +3719,8 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
                cmd = " FOR DELETE";
        else
        {
-               write_msg(NULL, "unexpected policy command type: %c\n",
-                                 polinfo->polcmd);
+               pg_log_error("unexpected policy command type: %c",
+                                        polinfo->polcmd);
                exit_nicely(1);
        }
 
@@ -3675,7 +3741,7 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
        if (polinfo->polwithcheck != NULL)
                appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
 
-       appendPQExpBuffer(query, ";\n");
+       appendPQExpBufferStr(query, ";\n");
 
        appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
        appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
@@ -3684,14 +3750,13 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 
        if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
                ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
-                                        tag,
-                                        polinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tbinfo->rolname, false,
-                                        "POLICY", SECTION_POST_DATA,
-                                        query->data, delqry->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag,
+                                                                 .namespace = polinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "POLICY",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = query->data,
+                                                                 .dropStmt = delqry->data));
 
        free(tag);
        destroyPQExpBuffer(query);
@@ -3781,8 +3846,8 @@ getPublications(Archive *fout)
                        (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
 
                if (strlen(pubinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
-                                         pubinfo[i].dobj.name);
+                       pg_log_warning("owner of publication \"%s\" appears to be invalid",
+                                                  pubinfo[i].dobj.name);
 
                /* Decide whether we want to dump it */
                selectDumpableObject(&(pubinfo[i].dobj), fout);
@@ -3858,14 +3923,12 @@ dumpPublication(Archive *fout, PublicationInfo *pubinfo)
        appendPQExpBufferStr(query, "');\n");
 
        ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
-                                pubinfo->dobj.name,
-                                NULL,
-                                NULL,
-                                pubinfo->rolname, false,
-                                "PUBLICATION", SECTION_POST_DATA,
-                                query->data, delq->data, NULL,
-                                NULL, 0,
-                                NULL, NULL);
+                                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,
@@ -3892,6 +3955,7 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
        PQExpBuffer query;
        PGresult   *res;
        PublicationRelInfo *pubrinfo;
+       DumpOptions *dopt = fout->dopt;
        int                     i_tableoid;
        int                     i_oid;
        int                     i_pubname;
@@ -3899,7 +3963,7 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
                                j,
                                ntups;
 
-       if (fout->remoteVersion < 100000)
+       if (dopt->no_publications || fout->remoteVersion < 100000)
                return;
 
        query = createPQExpBuffer();
@@ -3919,10 +3983,9 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
                if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
                        continue;
 
-               if (g_verbose)
-                       write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
-                                         tbinfo->dobj.namespace->dobj.name,
-                                         tbinfo->dobj.name);
+               pg_log_info("reading publication membership for table \"%s.%s\"",
+                                       tbinfo->dobj.namespace->dobj.name,
+                                       tbinfo->dobj.name);
 
                resetPQExpBuffer(query);
 
@@ -3996,18 +4059,15 @@ dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
                                          fmtQualifiedDumpable(tbinfo));
 
        /*
-        * There is no point in creating drop query as drop query as the drop is
-        * done by table drop.
+        * There is no point in creating drop query as the drop is done by table
+        * drop.
         */
        ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
-                                tag,
-                                tbinfo->dobj.namespace->dobj.name,
-                                NULL,
-                                "", false,
-                                "PUBLICATION TABLE", SECTION_POST_DATA,
-                                query->data, "", NULL,
-                                NULL, 0,
-                                NULL, NULL);
+                                ARCHIVE_OPTS(.tag = tag,
+                                                         .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                         .description = "PUBLICATION TABLE",
+                                                         .section = SECTION_POST_DATA,
+                                                         .createStmt = query->data));
 
        free(tag);
        destroyPQExpBuffer(query);
@@ -4066,7 +4126,7 @@ getSubscriptions(Archive *fout)
                                                          PGRES_TUPLES_OK);
                n = atoi(PQgetvalue(res, 0, 0));
                if (n > 0)
-                       write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
+                       pg_log_warning("subscriptions not dumped because current user is not a superuser");
                PQclear(res);
                return;
        }
@@ -4120,8 +4180,8 @@ getSubscriptions(Archive *fout)
                        pg_strdup(PQgetvalue(res, i, i_subpublications));
 
                if (strlen(subinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
-                                         subinfo[i].dobj.name);
+                       pg_log_warning("owner of subscription \"%s\" appears to be invalid",
+                                                  subinfo[i].dobj.name);
 
                /* Decide whether we want to dump it */
                selectDumpableObject(&(subinfo[i].dobj), fout);
@@ -4164,8 +4224,7 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
        /* Build list of quoted publications and append them to query. */
        if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
        {
-               write_msg(NULL,
-                                 "WARNING: could not parse subpublications array\n");
+               pg_log_warning("could not parse subpublications array");
                if (pubnames)
                        free(pubnames);
                pubnames = NULL;
@@ -4193,14 +4252,12 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
        appendPQExpBufferStr(query, ");\n");
 
        ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
-                                subinfo->dobj.name,
-                                NULL,
-                                NULL,
-                                subinfo->rolname, false,
-                                "SUBSCRIPTION", SECTION_POST_DATA,
-                                query->data, delq->data, NULL,
-                                NULL, 0,
-                                NULL, NULL);
+                                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,
@@ -4300,14 +4357,20 @@ binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
        Oid                     pg_type_oid;
        bool            toast_set = false;
 
-       /* we only support old >= 8.3 for binary upgrades */
+       /*
+        * We only support old >= 8.3 for binary upgrades.
+        *
+        * We purposefully ignore toast OIDs for partitioned tables; the reason is
+        * that versions 10 and 11 have them, but 12 does not, so emitting them
+        * causes the upgrade to fail.
+        */
        appendPQExpBuffer(upgrade_query,
                                          "SELECT c.reltype AS crel, t.reltype AS trel "
                                          "FROM pg_catalog.pg_class c "
                                          "LEFT JOIN pg_catalog.pg_class t ON "
-                                         "  (c.reltoastrelid = t.oid) "
+                                         "  (c.reltoastrelid = t.oid AND c.relkind <> '%c') "
                                          "WHERE c.oid = '%u'::pg_catalog.oid;",
-                                         pg_rel_oid);
+                                         RELKIND_PARTITIONED_TABLE, pg_rel_oid);
 
        upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
 
@@ -4433,8 +4496,8 @@ binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
                extobj = NULL;
        }
        if (extobj == NULL)
-               exit_horribly(NULL, "could not find parent extension for %s %s\n",
-                                         objtype, objname);
+               fatal("could not find parent extension for %s %s",
+                         objtype, objname);
 
        appendPQExpBufferStr(upgrade_buffer,
                                                 "\n-- For binary upgrade, handle extension membership the hard way\n");
@@ -4505,7 +4568,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
                                                  init_acl_subquery->data,
                                                  init_racl_subquery->data);
 
-               appendPQExpBuffer(query, ") ");
+               appendPQExpBufferStr(query, ") ");
 
                destroyPQExpBuffer(acl_subquery);
                destroyPQExpBuffer(racl_subquery);
@@ -4565,8 +4628,8 @@ getNamespaces(Archive *fout, int *numNamespaces)
                        nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
                if (strlen(nsinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
-                                         nsinfo[i].dobj.name);
+                       pg_log_warning("owner of schema \"%s\" appears to be invalid",
+                                                  nsinfo[i].dobj.name);
        }
 
        PQclear(res);
@@ -4588,7 +4651,7 @@ findNamespace(Archive *fout, Oid nsoid)
 
        nsinfo = findNamespaceByOid(nsoid);
        if (nsinfo == NULL)
-               exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
+               fatal("schema with OID %u does not exist", nsoid);
        return nsinfo;
 }
 
@@ -4913,8 +4976,8 @@ getTypes(Archive *fout, int *numTypes)
                }
 
                if (strlen(tyinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
-                                         tyinfo[i].dobj.name);
+                       pg_log_warning("owner of data type \"%s\" appears to be invalid",
+                                                  tyinfo[i].dobj.name);
        }
 
        *numTypes = ntups;
@@ -4998,8 +5061,8 @@ getOperators(Archive *fout, int *numOprs)
                oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
                if (strlen(oprinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
-                                         oprinfo[i].dobj.name);
+                       pg_log_warning("owner of operator \"%s\" appears to be invalid",
+                                                  oprinfo[i].dobj.name);
        }
 
        PQclear(res);
@@ -5193,9 +5256,9 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
        query = createPQExpBuffer();
 
        /* Select all access methods from pg_am table */
-       appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
-                                         "amhandler::pg_catalog.regproc AS amhandler "
-                                         "FROM pg_am");
+       appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
+                                                "amhandler::pg_catalog.regproc AS amhandler "
+                                                "FROM pg_am");
 
        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -5300,8 +5363,8 @@ getOpclasses(Archive *fout, int *numOpclasses)
                opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
                if (strlen(opcinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
-                                         opcinfo[i].dobj.name);
+                       pg_log_warning("owner of operator class \"%s\" appears to be invalid",
+                                                  opcinfo[i].dobj.name);
        }
 
        PQclear(res);
@@ -5384,8 +5447,8 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
                opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
                if (strlen(opfinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
-                                         opfinfo[i].dobj.name);
+                       pg_log_warning("owner of operator family \"%s\" appears to be invalid",
+                                                  opfinfo[i].dobj.name);
        }
 
        PQclear(res);
@@ -5553,8 +5616,8 @@ getAggregates(Archive *fout, int *numAggs)
                                                  atooid(PQgetvalue(res, i, i_aggnamespace)));
                agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
                if (strlen(agginfo[i].aggfn.rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
-                                         agginfo[i].aggfn.dobj.name);
+                       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));
@@ -5813,9 +5876,8 @@ getFuncs(Archive *fout, int *numFuncs)
                        finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
                if (strlen(finfo[i].rolname) == 0)
-                       write_msg(NULL,
-                                         "WARNING: owner of function \"%s\" appears to be invalid\n",
-                                         finfo[i].dobj.name);
+                       pg_log_warning("owner of function \"%s\" appears to be invalid",
+                                                  finfo[i].dobj.name);
        }
 
        PQclear(res);
@@ -5879,6 +5941,7 @@ getTables(Archive *fout, int *numTables)
        int                     i_partkeydef;
        int                     i_ispartition;
        int                     i_partbound;
+       int                     i_amname;
 
        /*
         * Find all the tables and table-like objects.
@@ -5898,6 +5961,10 @@ getTables(Archive *fout, int *numTables)
         * 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.
+        *
+        * We purposefully ignore toast OIDs for partitioned tables; the reason is
+        * that versions 10 and 11 have them, but 12 does not, so emitting them
+        * causes the upgrade to fail.
         */
 
        if (fout->remoteVersion >= 90600)
@@ -5905,6 +5972,7 @@ getTables(Archive *fout, int *numTables)
                char       *partkeydef = "NULL";
                char       *ispartition = "false";
                char       *partbound = "NULL";
+               char       *relhasoids = "c.relhasoids";
 
                PQExpBuffer acl_subquery = createPQExpBuffer();
                PQExpBuffer racl_subquery = createPQExpBuffer();
@@ -5928,6 +5996,10 @@ getTables(Archive *fout, int *numTables)
                        partbound = "pg_get_expr(c.relpartbound, c.oid)";
                }
 
+               /* In PG12 upwards WITH OIDS does not exist anymore. */
+               if (fout->remoteVersion >= 120000)
+                       relhasoids = "'f'::bool";
+
                /*
                 * Left join to pick up dependency info linking sequences to their
                 * owning column, if any (note this dependency is AUTO as of 8.2)
@@ -5953,13 +6025,13 @@ getTables(Archive *fout, int *numTables)
                                                  "c.relkind, c.relnamespace, "
                                                  "(%s c.relowner) AS rolname, "
                                                  "c.relchecks, c.relhastriggers, "
-                                                 "c.relhasindex, c.relhasrules, c.relhasoids, "
+                                                 "c.relhasindex, c.relhasrules, %s AS relhasoids, "
                                                  "c.relrowsecurity, c.relforcerowsecurity, "
                                                  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
                                                  "tc.relfrozenxid AS tfrozenxid, "
                                                  "tc.relminmxid AS tminmxid, "
                                                  "c.relpersistence, c.relispopulated, "
-                                                 "c.relreplident, c.relpages, "
+                                                 "c.relreplident, c.relpages, am.amname, "
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -5989,7 +6061,8 @@ getTables(Archive *fout, int *numTables)
                                                  "d.classid = c.tableoid AND d.objid = c.oid AND "
                                                  "d.objsubid = 0 AND "
                                                  "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
-                                                 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+                                                 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> '%c') "
+                                                 "LEFT JOIN pg_am am ON (c.relam = am.oid) "
                                                  "LEFT JOIN pg_init_privs pip ON "
                                                  "(c.oid = pip.objoid "
                                                  "AND pip.classoid = 'pg_class'::regclass "
@@ -6001,6 +6074,7 @@ getTables(Archive *fout, int *numTables)
                                                  initacl_subquery->data,
                                                  initracl_subquery->data,
                                                  username_subquery,
+                                                 relhasoids,
                                                  RELKIND_SEQUENCE,
                                                  attacl_subquery->data,
                                                  attracl_subquery->data,
@@ -6010,6 +6084,7 @@ getTables(Archive *fout, int *numTables)
                                                  ispartition,
                                                  partbound,
                                                  RELKIND_SEQUENCE,
+                                                 RELKIND_PARTITIONED_TABLE,
                                                  RELKIND_RELATION, RELKIND_SEQUENCE,
                                                  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
                                                  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
@@ -6046,6 +6121,7 @@ getTables(Archive *fout, int *numTables)
                                                  "tc.relminmxid AS tminmxid, "
                                                  "c.relpersistence, c.relispopulated, "
                                                  "c.relreplident, c.relpages, "
+                                                 "NULL AS amname, "
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6095,6 +6171,7 @@ getTables(Archive *fout, int *numTables)
                                                  "tc.relminmxid AS tminmxid, "
                                                  "c.relpersistence, c.relispopulated, "
                                                  "c.relreplident, c.relpages, "
+                                                 "NULL AS amname, "
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6144,6 +6221,7 @@ getTables(Archive *fout, int *numTables)
                                                  "tc.relminmxid AS tminmxid, "
                                                  "c.relpersistence, c.relispopulated, "
                                                  "'d' AS relreplident, c.relpages, "
+                                                 "NULL AS amname, "
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6193,6 +6271,7 @@ getTables(Archive *fout, int *numTables)
                                                  "0 AS tminmxid, "
                                                  "c.relpersistence, 't' as relispopulated, "
                                                  "'d' AS relreplident, c.relpages, "
+                                                 "NULL AS amname, "
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6240,6 +6319,7 @@ getTables(Archive *fout, int *numTables)
                                                  "0 AS tminmxid, "
                                                  "'p' AS relpersistence, 't' as relispopulated, "
                                                  "'d' AS relreplident, c.relpages, "
+                                                 "NULL AS amname, "
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6286,6 +6366,7 @@ getTables(Archive *fout, int *numTables)
                                                  "0 AS tminmxid, "
                                                  "'p' AS relpersistence, 't' as relispopulated, "
                                                  "'d' AS relreplident, c.relpages, "
+                                                 "NULL AS amname, "
                                                  "NULL AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6332,6 +6413,7 @@ getTables(Archive *fout, int *numTables)
                                                  "0 AS tminmxid, "
                                                  "'p' AS relpersistence, 't' as relispopulated, "
                                                  "'d' AS relreplident, c.relpages, "
+                                                 "NULL AS amname, "
                                                  "NULL AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6377,6 +6459,7 @@ getTables(Archive *fout, int *numTables)
                                                  "0 AS tfrozenxid, 0 AS tminmxid,"
                                                  "'p' AS relpersistence, 't' as relispopulated, "
                                                  "'d' AS relreplident, relpages, "
+                                                 "NULL AS amname, "
                                                  "NULL AS reloftype, "
                                                  "d.refobjid AS owning_tab, "
                                                  "d.refobjsubid AS owning_col, "
@@ -6456,6 +6539,7 @@ getTables(Archive *fout, int *numTables)
        i_partkeydef = PQfnumber(res, "partkeydef");
        i_ispartition = PQfnumber(res, "ispartition");
        i_partbound = PQfnumber(res, "partbound");
+       i_amname = PQfnumber(res, "amname");
 
        if (dopt->lockWaitTimeout)
        {
@@ -6525,6 +6609,10 @@ 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_amname))
+                       tblinfo[i].amname = NULL;
+               else
+                       tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
 
                /* other fields were zeroed above */
 
@@ -6592,8 +6680,8 @@ getTables(Archive *fout, int *numTables)
 
                /* Emit notice if join for owner failed */
                if (strlen(tblinfo[i].rolname) == 0)
-                       write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
-                                         tblinfo[i].dobj.name);
+                       pg_log_warning("owner of table \"%s\" appears to be invalid",
+                                                  tblinfo[i].dobj.name);
        }
 
        if (dopt->lockWaitTimeout)
@@ -6634,12 +6722,24 @@ getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
 
                owning_tab = findTableByOid(seqinfo->owning_tab);
                if (owning_tab == NULL)
-                       exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
-                                                 seqinfo->owning_tab, seqinfo->dobj.catId.oid);
+                       fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
+                                 seqinfo->owning_tab, seqinfo->dobj.catId.oid);
+
+               /*
+                * Only dump identity sequences if we're going to dump the table that
+                * it belongs to.
+                */
+               if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
+                       seqinfo->is_identity_sequence)
+               {
+                       seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
+                       continue;
+               }
 
                /*
-                * We need to dump the components that are being dumped for the table
-                * and any components which the sequence is explicitly marked with.
+                * Otherwise we need to dump the components that are being dumped for
+                * the table and any components which the sequence is explicitly
+                * marked with.
                 *
                 * We can't simply use the set of components which are being dumped
                 * for the table as the table might be in an extension (and only the
@@ -6680,9 +6780,7 @@ getInherits(Archive *fout, int *numInherits)
 
        /*
         * Find all the inheritance information, excluding implicit inheritance
-        * via partitioning.  We handle that case using getPartitions(), because
-        * we want more information about partitions than just the parent-child
-        * relationship.
+        * via partitioning.
         */
        appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
 
@@ -6745,7 +6843,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                i_condef,
                                i_tablespace,
                                i_indreloptions,
-                               i_relpages;
+                               i_indstatcols,
+                               i_indstatvals;
        int                     ntups;
 
        for (i = 0; i < numTables; i++)
@@ -6765,10 +6864,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                        !tbinfo->interesting)
                        continue;
 
-               if (g_verbose)
-                       write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
-                                         tbinfo->dobj.namespace->dobj.name,
-                                         tbinfo->dobj.name);
+               pg_log_info("reading indexes for table \"%s.%s\"",
+                                       tbinfo->dobj.namespace->dobj.name,
+                                       tbinfo->dobj.name);
 
                /*
                 * The point of the messy-looking outer join is to find a constraint
@@ -6792,14 +6890,22 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "i.indnkeyatts AS indnkeyatts, "
                                                          "i.indnatts AS indnatts, "
                                                          "i.indkey, i.indisclustered, "
-                                                         "i.indisreplident, t.relpages, "
+                                                         "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 "
+                                                         "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) "
@@ -6829,14 +6935,16 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "i.indnatts AS indnkeyatts, "
                                                          "i.indnatts AS indnatts, "
                                                          "i.indkey, i.indisclustered, "
-                                                         "i.indisreplident, t.relpages, "
+                                                         "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 "
+                                                         "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 "
@@ -6862,14 +6970,16 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "i.indnatts AS indnkeyatts, "
                                                          "i.indnatts AS indnatts, "
                                                          "i.indkey, i.indisclustered, "
-                                                         "false AS indisreplident, t.relpages, "
+                                                         "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 "
+                                                         "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 "
@@ -6891,14 +7001,16 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "i.indnatts AS indnkeyatts, "
                                                          "i.indnatts AS indnatts, "
                                                          "i.indkey, i.indisclustered, "
-                                                         "false AS indisreplident, t.relpages, "
+                                                         "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 "
+                                                         "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 "
@@ -6923,14 +7035,16 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                                                          "t.relnatts AS indnkeyatts, "
                                                          "t.relnatts AS indnatts, "
                                                          "i.indkey, i.indisclustered, "
-                                                         "false AS indisreplident, t.relpages, "
+                                                         "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 "
+                                                         "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 "
@@ -6959,7 +7073,6 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                i_indkey = PQfnumber(res, "indkey");
                i_indisclustered = PQfnumber(res, "indisclustered");
                i_indisreplident = PQfnumber(res, "indisreplident");
-               i_relpages = PQfnumber(res, "relpages");
                i_contype = PQfnumber(res, "contype");
                i_conname = PQfnumber(res, "conname");
                i_condeferrable = PQfnumber(res, "condeferrable");
@@ -6969,6 +7082,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                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));
@@ -6992,13 +7107,14 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                        indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
                        indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
                        indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
+                       indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
+                       indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
                        indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
                        parseOidArray(PQgetvalue(res, j, i_indkey),
                                                  indxinfo[j].indkeys, indxinfo[j].indnattrs);
                        indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
                        indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
                        indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
-                       indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
                        contype = *(PQgetvalue(res, j, i_contype));
 
                        if (contype == 'p' || contype == 'u' || contype == 'x')
@@ -7149,10 +7265,9 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
                        !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
                        continue;
 
-               if (g_verbose)
-                       write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
-                                         tbinfo->dobj.namespace->dobj.name,
-                                         tbinfo->dobj.name);
+               pg_log_info("reading foreign key constraints for table \"%s.%s\"",
+                                       tbinfo->dobj.namespace->dobj.name,
+                                       tbinfo->dobj.name);
 
                resetPQExpBuffer(query);
                if (fout->remoteVersion >= 110000)
@@ -7369,8 +7484,8 @@ getRules(Archive *fout, int *numRules)
                ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
                ruleinfo[i].ruletable = findTableByOid(ruletableoid);
                if (ruleinfo[i].ruletable == NULL)
-                       exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
-                                                 ruletableoid, ruleinfo[i].dobj.catId.oid);
+                       fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
+                                 ruletableoid, ruleinfo[i].dobj.catId.oid);
                ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
                ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
                ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
@@ -7452,10 +7567,9 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
                        !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
                        continue;
 
-               if (g_verbose)
-                       write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
-                                         tbinfo->dobj.namespace->dobj.name,
-                                         tbinfo->dobj.name);
+               pg_log_info("reading triggers for table \"%s.%s\"",
+                                       tbinfo->dobj.namespace->dobj.name,
+                                       tbinfo->dobj.name);
 
                resetPQExpBuffer(query);
                if (fout->remoteVersion >= 90000)
@@ -7586,10 +7700,10 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
                                        if (OidIsValid(tginfo[j].tgconstrrelid))
                                        {
                                                if (PQgetisnull(res, j, i_tgconstrrelname))
-                                                       exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
-                                                                                 tginfo[j].dobj.name,
-                                                                                 tbinfo->dobj.name,
-                                                                                 tginfo[j].tgconstrrelid);
+                                                       fatal("query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)",
+                                                                 tginfo[j].dobj.name,
+                                                                 tbinfo->dobj.name,
+                                                                 tginfo[j].tgconstrrelid);
                                                tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
                                        }
                                        else
@@ -8020,10 +8134,10 @@ getTransforms(Archive *fout, int *numTransforms)
 
        query = createPQExpBuffer();
 
-       appendPQExpBuffer(query, "SELECT tableoid, oid, "
-                                         "trftype, trflang, trffromsql::oid, trftosql::oid "
-                                         "FROM pg_transform "
-                                         "ORDER BY 3,4");
+       appendPQExpBufferStr(query, "SELECT tableoid, oid, "
+                                                "trftype, trflang, trffromsql::oid, trftosql::oid "
+                                                "FROM pg_transform "
+                                                "ORDER BY 3,4");
 
        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -8110,6 +8224,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
        int                     i_attnotnull;
        int                     i_atthasdef;
        int                     i_attidentity;
+       int                     i_attgenerated;
        int                     i_attisdropped;
        int                     i_attlen;
        int                     i_attalign;
@@ -8140,157 +8255,92 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                 * we must read the attribute names in attribute number order! because
                 * we will use the attnum to index into the attnames array later.
                 */
-               if (g_verbose)
-                       write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
-                                         tbinfo->dobj.namespace->dobj.name,
-                                         tbinfo->dobj.name);
+               pg_log_info("finding the columns and types of table \"%s.%s\"",
+                                       tbinfo->dobj.namespace->dobj.name,
+                                       tbinfo->dobj.name);
 
                resetPQExpBuffer(q);
 
+               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 >= 120000)
+                       appendPQExpBufferStr(q,
+                                                                "a.attgenerated,\n");
+               else
+                       appendPQExpBufferStr(q,
+                                                                "'' AS attgenerated,\n");
+
                if (fout->remoteVersion >= 110000)
-               {
-                       /* atthasmissing and attmissingval are new in 11 */
-                       appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
-                                                         "a.attstattarget, a.attstorage, t.typstorage, "
-                                                         "a.attnotnull, a.atthasdef, a.attisdropped, "
-                                                         "a.attlen, a.attalign, a.attislocal, "
-                                                         "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                                                         "array_to_string(a.attoptions, ', ') AS attoptions, "
-                                                         "CASE WHEN a.attcollation <> t.typcollation "
-                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
-                                                         "a.attidentity, "
-                                                         "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 ,"
-                                                         "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
-                                                         "THEN a.attmissingval ELSE null END AS attmissingval "
-                                                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
-                                                         "ON a.atttypid = t.oid "
-                                                         "WHERE a.attrelid = '%u'::pg_catalog.oid "
-                                                         "AND a.attnum > 0::pg_catalog.int2 "
-                                                         "ORDER BY a.attnum",
-                                                         tbinfo->dobj.catId.oid);
-               }
-               else if (fout->remoteVersion >= 100000)
-               {
-                       /*
-                        * attidentity is new in version 10.
-                        */
-                       appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
-                                                         "a.attstattarget, a.attstorage, t.typstorage, "
-                                                         "a.attnotnull, a.atthasdef, a.attisdropped, "
-                                                         "a.attlen, a.attalign, a.attislocal, "
-                                                         "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                                                         "array_to_string(a.attoptions, ', ') AS attoptions, "
-                                                         "CASE WHEN a.attcollation <> t.typcollation "
-                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
-                                                         "a.attidentity, "
-                                                         "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 ,"
-                                                         "NULL as attmissingval "
-                                                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
-                                                         "ON a.atttypid = t.oid "
-                                                         "WHERE a.attrelid = '%u'::pg_catalog.oid "
-                                                         "AND a.attnum > 0::pg_catalog.int2 "
-                                                         "ORDER BY a.attnum",
-                                                         tbinfo->dobj.catId.oid);
-               }
-               else if (fout->remoteVersion >= 90200)
-               {
-                       /*
-                        * attfdwoptions is new in 9.2.
-                        */
-                       appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
-                                                         "a.attstattarget, a.attstorage, t.typstorage, "
-                                                         "a.attnotnull, a.atthasdef, a.attisdropped, "
-                                                         "a.attlen, a.attalign, a.attislocal, "
-                                                         "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                                                         "array_to_string(a.attoptions, ', ') AS attoptions, "
-                                                         "CASE WHEN a.attcollation <> t.typcollation "
-                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
-                                                         "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, "
-                                                         "NULL as attmissingval "
-                                                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
-                                                         "ON a.atttypid = t.oid "
-                                                         "WHERE a.attrelid = '%u'::pg_catalog.oid "
-                                                         "AND a.attnum > 0::pg_catalog.int2 "
-                                                         "ORDER BY a.attnum",
-                                                         tbinfo->dobj.catId.oid);
-               }
-               else if (fout->remoteVersion >= 90100)
+                       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 >= 100000)
+                       appendPQExpBufferStr(q,
+                                                                "a.attidentity,\n");
+               else
+                       appendPQExpBufferStr(q,
+                                                                "'' AS attidentity,\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 >= 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.
+                        * 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.
                         */
-                       appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
-                                                         "a.attstattarget, a.attstorage, t.typstorage, "
-                                                         "a.attnotnull, a.atthasdef, a.attisdropped, "
-                                                         "a.attlen, a.attalign, a.attislocal, "
-                                                         "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                                                         "array_to_string(a.attoptions, ', ') AS attoptions, "
-                                                         "CASE WHEN a.attcollation <> t.typcollation "
-                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
-                                                         "NULL AS attfdwoptions, "
-                                                         "NULL as attmissingval "
-                                                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
-                                                         "ON a.atttypid = t.oid "
-                                                         "WHERE a.attrelid = '%u'::pg_catalog.oid "
-                                                         "AND a.attnum > 0::pg_catalog.int2 "
-                                                         "ORDER BY a.attnum",
-                                                         tbinfo->dobj.catId.oid);
-               }
-               else if (fout->remoteVersion >= 90000)
-               {
-                       /* attoptions is new in 9.0 */
-                       appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
-                                                         "a.attstattarget, a.attstorage, t.typstorage, "
-                                                         "a.attnotnull, a.atthasdef, a.attisdropped, "
-                                                         "a.attlen, a.attalign, a.attislocal, "
-                                                         "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                                                         "array_to_string(a.attoptions, ', ') AS attoptions, "
-                                                         "0 AS attcollation, "
-                                                         "NULL AS attfdwoptions, "
-                                                         "NULL as attmissingval "
-                                                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
-                                                         "ON a.atttypid = t.oid "
-                                                         "WHERE a.attrelid = '%u'::pg_catalog.oid "
-                                                         "AND a.attnum > 0::pg_catalog.int2 "
-                                                         "ORDER BY a.attnum",
-                                                         tbinfo->dobj.catId.oid);
+                       appendPQExpBufferStr(q,
+                                                                "CASE WHEN a.attcollation <> t.typcollation "
+                                                                "THEN a.attcollation ELSE 0 END AS attcollation,\n");
                }
                else
-               {
-                       /* need left join here to not fail on dropped columns ... */
-                       appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
-                                                         "a.attstattarget, a.attstorage, t.typstorage, "
-                                                         "a.attnotnull, a.atthasdef, a.attisdropped, "
-                                                         "a.attlen, a.attalign, a.attislocal, "
-                                                         "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
-                                                         "'' AS attoptions, 0 AS attcollation, "
-                                                         "NULL AS attfdwoptions, "
-                                                         "NULL as attmissingval "
-                                                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
-                                                         "ON a.atttypid = t.oid "
-                                                         "WHERE a.attrelid = '%u'::pg_catalog.oid "
-                                                         "AND a.attnum > 0::pg_catalog.int2 "
-                                                         "ORDER BY a.attnum",
-                                                         tbinfo->dobj.catId.oid);
-               }
+                       appendPQExpBufferStr(q,
+                                                                "0 AS attcollation,\n");
+
+               if (fout->remoteVersion >= 90000)
+                       appendPQExpBufferStr(q,
+                                                                "array_to_string(a.attoptions, ', ') AS attoptions\n");
+               else
+                       appendPQExpBufferStr(q,
+                                                                "'' AS attoptions\n");
+
+               /* 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);
 
                res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
 
@@ -8306,6 +8356,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                i_attnotnull = PQfnumber(res, "attnotnull");
                i_atthasdef = PQfnumber(res, "atthasdef");
                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");
@@ -8323,6 +8374,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                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));
@@ -8339,16 +8391,16 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                for (j = 0; j < ntups; j++)
                {
                        if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
-                               exit_horribly(NULL,
-                                                         "invalid column numbering in table \"%s\"\n",
-                                                         tbinfo->dobj.name);
+                               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] = (i_attidentity >= 0 ? *(PQgetvalue(res, j, i_attidentity)) : '\0');
+                       tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
+                       tbinfo->attgenerated[j] = *(PQgetvalue(res, j, 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));
@@ -8376,10 +8428,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                        AttrDefInfo *attrdefs;
                        int                     numDefaults;
 
-                       if (g_verbose)
-                               write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
-                                                 tbinfo->dobj.namespace->dobj.name,
-                                                 tbinfo->dobj.name);
+                       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 "
@@ -8399,9 +8450,8 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                                adnum = atoi(PQgetvalue(res, j, 2));
 
                                if (adnum <= 0 || adnum > ntups)
-                                       exit_horribly(NULL,
-                                                                 "invalid adnum value %d for table \"%s\"\n",
-                                                                 adnum, tbinfo->dobj.name);
+                                       fatal("invalid adnum value %d for table \"%s\"",
+                                                 adnum, tbinfo->dobj.name);
 
                                /*
                                 * dropped columns shouldn't have defaults, but just in case,
@@ -8465,10 +8515,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                        ConstraintInfo *constrs;
                        int                     numConstrs;
 
-                       if (g_verbose)
-                               write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
-                                                 tbinfo->dobj.namespace->dobj.name,
-                                                 tbinfo->dobj.name);
+                       pg_log_info("finding check constraints for table \"%s.%s\"",
+                                               tbinfo->dobj.namespace->dobj.name,
+                                               tbinfo->dobj.name);
 
                        resetPQExpBuffer(q);
                        if (fout->remoteVersion >= 90200)
@@ -8515,11 +8564,11 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
                        numConstrs = PQntuples(res);
                        if (numConstrs != tbinfo->ncheck)
                        {
-                               write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
-                                                                                "expected %d check constraints on table \"%s\" but found %d\n",
-                                                                                tbinfo->ncheck),
-                                                 tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
-                               write_msg(NULL, "(The system catalogs might be corrupted.)\n");
+                               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);
+                               pg_log_error("(The system catalogs might be corrupted.)");
                                exit_nicely(1);
                        }
 
@@ -8588,9 +8637,12 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
  * Normally this is always true, but it's false for dropped columns, as well
  * as those that were inherited without any local definition.  (If we print
  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
- * However, in binary_upgrade mode, we must print all such columns anyway and
- * fix the attislocal/attisdropped state later, so as to keep control of the
- * physical column order.
+ * For partitions, it's always true, because we want the partitions to be
+ * created independently and ATTACH PARTITION used afterwards.
+ *
+ * In binary_upgrade mode, we must print all columns and fix the attislocal/
+ * attisdropped state later, so as to keep control of the physical column
+ * order.
  *
  * This function exists because there are scattered nonobvious places that
  * must be kept in sync with this decision.
@@ -8600,7 +8652,9 @@ shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
 {
        if (dopt->binary_upgrade)
                return true;
-       return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
+       if (tbinfo->attisdropped[colno])
+               return false;
+       return (tbinfo->attislocal[colno] || tbinfo->ispartition);
 }
 
 
@@ -9461,11 +9515,14 @@ dumpComment(Archive *fout, const char *type, const char *name,
                 * post-data.
                 */
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        tag->data, namespace, NULL, owner,
-                                        false, "COMMENT", SECTION_NONE,
-                                        query->data, "", NULL,
-                                        &(dumpId), 1,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag->data,
+                                                                 .namespace = namespace,
+                                                                 .owner = owner,
+                                                                 .description = "COMMENT",
+                                                                 .section = SECTION_NONE,
+                                                                 .createStmt = query->data,
+                                                                 .deps = &dumpId,
+                                                                 .nDeps = 1));
 
                destroyPQExpBuffer(query);
                destroyPQExpBuffer(tag);
@@ -9527,13 +9584,14 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
                        appendPQExpBufferStr(query, ";\n");
 
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                                tag->data,
-                                                tbinfo->dobj.namespace->dobj.name,
-                                                NULL, tbinfo->rolname,
-                                                false, "COMMENT", SECTION_NONE,
-                                                query->data, "", NULL,
-                                                &(tbinfo->dobj.dumpId), 1,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = tag->data,
+                                                                         .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                         .owner = tbinfo->rolname,
+                                                                         .description = "COMMENT",
+                                                                         .section = SECTION_NONE,
+                                                                         .createStmt = query->data,
+                                                                         .deps = &(tbinfo->dobj.dumpId),
+                                                                         .nDeps = 1));
                }
                else if (objsubid > 0 && objsubid <= tbinfo->numatts)
                {
@@ -9551,13 +9609,14 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
                        appendPQExpBufferStr(query, ";\n");
 
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                                tag->data,
-                                                tbinfo->dobj.namespace->dobj.name,
-                                                NULL, tbinfo->rolname,
-                                                false, "COMMENT", SECTION_NONE,
-                                                query->data, "", NULL,
-                                                &(tbinfo->dobj.dumpId), 1,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = tag->data,
+                                                                         .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                         .owner = tbinfo->rolname,
+                                                                         .description = "COMMENT",
+                                                                         .section = SECTION_NONE,
+                                                                         .createStmt = query->data,
+                                                                         .deps = &(tbinfo->dobj.dumpId),
+                                                                         .nDeps = 1));
                }
 
                comments++;
@@ -9830,12 +9889,30 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
                        break;
                case DO_BLOB_DATA:
                        if (dobj->dump & DUMP_COMPONENT_DATA)
-                               ArchiveEntry(fout, dobj->catId, dobj->dumpId,
-                                                        dobj->name, NULL, NULL, "",
-                                                        false, "BLOBS", SECTION_DATA,
-                                                        "", "", NULL,
-                                                        NULL, 0,
-                                                        dumpBlobs, NULL);
+                       {
+                               TocEntry   *te;
+
+                               te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
+                                                                 ARCHIVE_OPTS(.tag = dobj->name,
+                                                                                          .description = "BLOBS",
+                                                                                          .section = SECTION_DATA,
+                                                                                          .dumpFn = dumpBlobs));
+
+                               /*
+                                * Set the TocEntry's dataLength in case we are doing a
+                                * parallel dump and want to order dump jobs by table size.
+                                * (We need some size estimate for every TocEntry with a
+                                * DataDumper function.)  We don't currently have any cheap
+                                * way to estimate the size of blobs, but it doesn't matter;
+                                * let's just set the size to a large value so parallel dumps
+                                * will launch this job first.  If there's lots of blobs, we
+                                * win, and if there aren't, we don't lose much.  (If you want
+                                * to improve on this, really what you should be thinking
+                                * about is allowing blob dumping to be parallelized, not just
+                                * getting a smarter estimate for the single TOC entry.)
+                                */
+                               te->dataLength = MaxBlockNumber;
+                       }
                        break;
                case DO_POLICY:
                        dumpPolicy(fout, (PolicyInfo *) dobj);
@@ -9887,13 +9964,12 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 
        if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
-                                        nspinfo->dobj.name,
-                                        NULL, NULL,
-                                        nspinfo->rolname,
-                                        false, "SCHEMA", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
+                                                                 .owner = nspinfo->rolname,
+                                                                 .description = "SCHEMA",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Schema Comments and Security Labels */
        if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -10023,13 +10099,11 @@ dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
        if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
-                                        extinfo->dobj.name,
-                                        NULL, NULL,
-                                        "",
-                                        false, "EXTENSION", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = extinfo->dobj.name,
+                                                                 .description = "EXTENSION",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Extension Comments and Security Labels */
        if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -10075,8 +10149,8 @@ dumpType(Archive *fout, TypeInfo *tyinfo)
        else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
                dumpUndefinedType(fout, tyinfo);
        else
-               write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
-                                 tyinfo->dobj.name);
+               pg_log_warning("typtype of data type \"%s\" appears to be invalid",
+                                          tyinfo->dobj.name);
 }
 
 /*
@@ -10173,14 +10247,13 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 
        if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-                                        tyinfo->dobj.name,
-                                        tyinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tyinfo->rolname, false,
-                                        "TYPE", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
+                                                                 .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tyinfo->rolname,
+                                                                 .description = "TYPE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Type Comments and Security Labels */
        if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -10300,14 +10373,13 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
 
        if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-                                        tyinfo->dobj.name,
-                                        tyinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tyinfo->rolname, false,
-                                        "TYPE", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
+                                                                 .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tyinfo->rolname,
+                                                                 .description = "TYPE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Type Comments and Security Labels */
        if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -10373,14 +10445,13 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
 
        if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-                                        tyinfo->dobj.name,
-                                        tyinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tyinfo->rolname, false,
-                                        "TYPE", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
+                                                                 .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tyinfo->rolname,
+                                                                 .description = "TYPE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Type Comments and Security Labels */
        if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -10655,14 +10726,13 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 
        if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-                                        tyinfo->dobj.name,
-                                        tyinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tyinfo->rolname, false,
-                                        "TYPE", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
+                                                                 .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tyinfo->rolname,
+                                                                 .description = "TYPE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Type Comments and Security Labels */
        if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -10812,14 +10882,13 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo)
 
        if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-                                        tyinfo->dobj.name,
-                                        tyinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tyinfo->rolname, false,
-                                        "DOMAIN", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
+                                                                 .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tyinfo->rolname,
+                                                                 .description = "DOMAIN",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Domain Comments and Security Labels */
        if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -11034,14 +11103,13 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 
        if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
-                                        tyinfo->dobj.name,
-                                        tyinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tyinfo->rolname, false,
-                                        "TYPE", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
+                                                                 .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tyinfo->rolname,
+                                                                 .description = "TYPE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
 
        /* Dump Type Comments and Security Labels */
@@ -11170,13 +11238,14 @@ dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
                        appendPQExpBufferStr(query, ";\n");
 
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                                target->data,
-                                                tyinfo->dobj.namespace->dobj.name,
-                                                NULL, tyinfo->rolname,
-                                                false, "COMMENT", SECTION_NONE,
-                                                query->data, "", NULL,
-                                                &(tyinfo->dobj.dumpId), 1,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = target->data,
+                                                                         .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                         .owner = tyinfo->rolname,
+                                                                         .description = "COMMENT",
+                                                                         .section = SECTION_NONE,
+                                                                         .createStmt = query->data,
+                                                                         .deps = &(tyinfo->dobj.dumpId),
+                                                                         .nDeps = 1));
                }
 
                comments++;
@@ -11225,14 +11294,12 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 
        if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
-                                        stinfo->dobj.name,
-                                        stinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        stinfo->baseType->rolname, false,
-                                        "SHELL TYPE", SECTION_PRE_DATA,
-                                        q->data, "", NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = stinfo->dobj.name,
+                                                                 .namespace = stinfo->dobj.namespace->dobj.name,
+                                                                 .owner = stinfo->baseType->rolname,
+                                                                 .description = "SHELL TYPE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data));
 
        destroyPQExpBuffer(q);
 }
@@ -11337,12 +11404,13 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
 
        if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
-                                        plang->dobj.name,
-                                        NULL, NULL, plang->lanowner,
-                                        false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
-                                        defqry->data, delqry->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = plang->dobj.name,
+                                                                 .owner = plang->lanowner,
+                                                                 .description = "PROCEDURAL LANGUAGE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = defqry->data,
+                                                                 .dropStmt = delqry->data,
+                                                                 ));
 
        /* Dump Proc Lang Comments and Security Labels */
        if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -11435,7 +11503,7 @@ format_function_arguments_old(Archive *fout,
                                        argmode = "INOUT ";
                                        break;
                                default:
-                                       write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
+                                       pg_log_warning("bogus value in proargmodes array");
                                        argmode = "";
                                        break;
                        }
@@ -11531,6 +11599,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
        char       *proconfig;
        char       *procost;
        char       *prorows;
+       char       *prosupport;
        char       *proparallel;
        char       *lanname;
        char       *rettypename;
@@ -11553,7 +11622,26 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
        asPart = createPQExpBuffer();
 
        /* Fetch function-specific details */
-       if (fout->remoteVersion >= 110000)
+       if (fout->remoteVersion >= 120000)
+       {
+               /*
+                * prosupport was added in 12
+                */
+               appendPQExpBuffer(query,
+                                                 "SELECT proretset, prosrc, probin, "
+                                                 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
+                                                 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
+                                                 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
+                                                 "array_to_string(protrftypes, ' ') AS protrftypes, "
+                                                 "prokind, provolatile, proisstrict, prosecdef, "
+                                                 "proleakproof, proconfig, procost, prorows, "
+                                                 "prosupport, proparallel, "
+                                                 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
+                                                 "FROM pg_catalog.pg_proc "
+                                                 "WHERE oid = '%u'::pg_catalog.oid",
+                                                 finfo->dobj.catId.oid);
+       }
+       else if (fout->remoteVersion >= 110000)
        {
                /*
                 * prokind was added in 11
@@ -11566,7 +11654,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "array_to_string(protrftypes, ' ') AS protrftypes, "
                                                  "prokind, provolatile, proisstrict, prosecdef, "
                                                  "proleakproof, proconfig, procost, prorows, "
-                                                 "proparallel, "
+                                                 "'-' AS prosupport, proparallel, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11586,7 +11674,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "proleakproof, proconfig, procost, prorows, "
-                                                 "proparallel, "
+                                                 "'-' AS prosupport, proparallel, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11606,6 +11694,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "proleakproof, proconfig, procost, prorows, "
+                                                 "'-' AS prosupport, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11624,6 +11713,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "proleakproof, proconfig, procost, prorows, "
+                                                 "'-' AS prosupport, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11644,6 +11734,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "false AS proleakproof, "
                                                  " proconfig, procost, prorows, "
+                                                 "'-' AS prosupport, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11658,6 +11749,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "false AS proleakproof, "
                                                  "proconfig, procost, prorows, "
+                                                 "'-' AS prosupport, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11672,6 +11764,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "false AS proleakproof, "
                                                  "null AS proconfig, 0 AS procost, 0 AS prorows, "
+                                                 "'-' AS prosupport, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11688,6 +11781,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                                                  "provolatile, proisstrict, prosecdef, "
                                                  "false AS proleakproof, "
                                                  "null AS proconfig, 0 AS procost, 0 AS prorows, "
+                                                 "'-' AS prosupport, "
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
                                                  "FROM pg_catalog.pg_proc "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -11725,6 +11819,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
        proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
        procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
        prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
+       prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
 
        if (PQfnumber(res, "proparallel") != -1)
                proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
@@ -11780,7 +11875,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
                        nitems < finfo->nargs)
                {
-                       write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
+                       pg_log_warning("could not parse proallargtypes array");
                        if (allargtypes)
                                free(allargtypes);
                        allargtypes = NULL;
@@ -11796,7 +11891,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
                        nitems != nallargs)
                {
-                       write_msg(NULL, "WARNING: could not parse proargmodes array\n");
+                       pg_log_warning("could not parse proargmodes array");
                        if (argmodes)
                                free(argmodes);
                        argmodes = NULL;
@@ -11810,7 +11905,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                if (!parsePGArray(proargnames, &argnames, &nitems) ||
                        nitems != nallargs)
                {
-                       write_msg(NULL, "WARNING: could not parse proargnames array\n");
+                       pg_log_warning("could not parse proargnames array");
                        if (argnames)
                                free(argnames);
                        argnames = NULL;
@@ -11821,7 +11916,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
        {
                if (!parsePGArray(proconfig, &configitems, &nconfigitems))
                {
-                       write_msg(NULL, "WARNING: could not parse proconfig array\n");
+                       pg_log_warning("could not parse proconfig array");
                        if (configitems)
                                free(configitems);
                        configitems = NULL;
@@ -11901,8 +11996,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                else if (provolatile[0] == PROVOLATILE_STABLE)
                        appendPQExpBufferStr(q, " STABLE");
                else if (provolatile[0] != PROVOLATILE_VOLATILE)
-                       exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
-                                                 finfo->dobj.name);
+                       fatal("unrecognized provolatile value for function \"%s\"",
+                                 finfo->dobj.name);
        }
 
        if (proisstrict[0] == 't')
@@ -11938,6 +12033,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
                appendPQExpBuffer(q, " ROWS %s", prorows);
 
+       if (strcmp(prosupport, "-") != 0)
+       {
+               /* We rely on regprocout to provide quoting and qualification */
+               appendPQExpBuffer(q, " SUPPORT %s", prosupport);
+       }
+
        if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
        {
                if (proparallel[0] == PROPARALLEL_SAFE)
@@ -11945,8 +12046,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                else if (proparallel[0] == PROPARALLEL_RESTRICTED)
                        appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
                else if (proparallel[0] != PROPARALLEL_UNSAFE)
-                       exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
-                                                 finfo->dobj.name);
+                       fatal("unrecognized proparallel value for function \"%s\"",
+                                 finfo->dobj.name);
        }
 
        for (i = 0; i < nconfigitems; i++)
@@ -12007,14 +12108,13 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 
        if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
-                                        funcsig_tag,
-                                        finfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        finfo->rolname, false,
-                                        keyword, SECTION_PRE_DATA,
-                                        q->data, delqry->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = funcsig_tag,
+                                                                 .namespace = finfo->dobj.namespace->dobj.name,
+                                                                 .owner = finfo->rolname,
+                                                                 .description = keyword,
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delqry->data));
 
        /* Dump Function Comments and Security Labels */
        if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -12079,8 +12179,8 @@ dumpCast(Archive *fout, CastInfo *cast)
        {
                funcInfo = findFuncByOid(cast->castfunc);
                if (funcInfo == NULL)
-                       exit_horribly(NULL, "could not find function definition for function with OID %u\n",
-                                                 cast->castfunc);
+                       fatal("could not find function definition for function with OID %u",
+                                 cast->castfunc);
        }
 
        defqry = createPQExpBuffer();
@@ -12118,10 +12218,10 @@ dumpCast(Archive *fout, CastInfo *cast)
                                free(fsig);
                        }
                        else
-                               write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
+                               pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
                        break;
                default:
-                       write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
+                       pg_log_warning("bogus value in pg_cast.castmethod field");
        }
 
        if (cast->castcontext == 'a')
@@ -12142,12 +12242,11 @@ dumpCast(Archive *fout, CastInfo *cast)
 
        if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
-                                        labelq->data,
-                                        NULL, NULL, "",
-                                        false, "CAST", SECTION_PRE_DATA,
-                                        defqry->data, delqry->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = labelq->data,
+                                                                 .description = "CAST",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = defqry->data,
+                                                                 .dropStmt = delqry->data));
 
        /* Dump Cast Comments */
        if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -12189,15 +12288,15 @@ dumpTransform(Archive *fout, TransformInfo *transform)
        {
                fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
                if (fromsqlFuncInfo == NULL)
-                       exit_horribly(NULL, "could not find function definition for function with OID %u\n",
-                                                 transform->trffromsql);
+                       fatal("could not find function definition for function with OID %u",
+                                 transform->trffromsql);
        }
        if (OidIsValid(transform->trftosql))
        {
                tosqlFuncInfo = findFuncByOid(transform->trftosql);
                if (tosqlFuncInfo == NULL)
-                       exit_horribly(NULL, "could not find function definition for function with OID %u\n",
-                                                 transform->trftosql);
+                       fatal("could not find function definition for function with OID %u",
+                                 transform->trftosql);
        }
 
        defqry = createPQExpBuffer();
@@ -12215,7 +12314,7 @@ dumpTransform(Archive *fout, TransformInfo *transform)
                                          transformType, lanname);
 
        if (!transform->trffromsql && !transform->trftosql)
-               write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
+               pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
 
        if (transform->trffromsql)
        {
@@ -12232,13 +12331,13 @@ dumpTransform(Archive *fout, TransformInfo *transform)
                        free(fsig);
                }
                else
-                       write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
+                       pg_log_warning("bogus value in pg_transform.trffromsql field");
        }
 
        if (transform->trftosql)
        {
                if (transform->trffromsql)
-                       appendPQExpBuffer(defqry, ", ");
+                       appendPQExpBufferStr(defqry, ", ");
 
                if (tosqlFuncInfo)
                {
@@ -12253,10 +12352,10 @@ dumpTransform(Archive *fout, TransformInfo *transform)
                        free(fsig);
                }
                else
-                       write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
+                       pg_log_warning("bogus value in pg_transform.trftosql field");
        }
 
-       appendPQExpBuffer(defqry, ");\n");
+       appendPQExpBufferStr(defqry, ");\n");
 
        appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
                                          transformType, lanname);
@@ -12270,12 +12369,13 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 
        if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
-                                        labelq->data,
-                                        NULL, NULL, "",
-                                        false, "TRANSFORM", SECTION_PRE_DATA,
-                                        defqry->data, delqry->data, NULL,
-                                        transform->dobj.dependencies, transform->dobj.nDeps,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = labelq->data,
+                                                                 .description = "TRANSFORM",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = defqry->data,
+                                                                 .dropStmt = delqry->data,
+                                                                 .deps = transform->dobj.dependencies,
+                                                                 .nDeps = transform->dobj.nDeps));
 
        /* Dump Transform Comments */
        if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -12405,7 +12505,7 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
        oprregproc = convertRegProcReference(fout, oprcode);
        if (oprregproc)
        {
-               appendPQExpBuffer(details, "    PROCEDURE = %s", oprregproc);
+               appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
                free(oprregproc);
        }
 
@@ -12483,14 +12583,13 @@ dumpOpr(Archive *fout, OprInfo *oprinfo)
 
        if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
-                                        oprinfo->dobj.name,
-                                        oprinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        oprinfo->rolname,
-                                        false, "OPERATOR", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
+                                                                 .namespace = oprinfo->dobj.namespace->dobj.name,
+                                                                 .owner = oprinfo->rolname,
+                                                                 .description = "OPERATOR",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Operator Comments */
        if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -12569,8 +12668,8 @@ getFormattedOperatorName(Archive *fout, const char *oproid)
        oprInfo = findOprByOid(atooid(oproid));
        if (oprInfo == NULL)
        {
-               write_msg(NULL, "WARNING: could not find operator with OID %s\n",
-                                 oproid);
+               pg_log_warning("could not find operator with OID %s",
+                                          oproid);
                return NULL;
        }
 
@@ -12631,11 +12730,14 @@ dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
        switch (aminfo->amtype)
        {
                case AMTYPE_INDEX:
-                       appendPQExpBuffer(q, "TYPE INDEX ");
+                       appendPQExpBufferStr(q, "TYPE INDEX ");
+                       break;
+               case AMTYPE_TABLE:
+                       appendPQExpBufferStr(q, "TYPE TABLE ");
                        break;
                default:
-                       write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
-                                         aminfo->amtype, qamname);
+                       pg_log_warning("invalid type \"%c\" of access method \"%s\"",
+                                                  aminfo->amtype, qamname);
                        destroyPQExpBuffer(q);
                        destroyPQExpBuffer(delq);
                        free(qamname);
@@ -12653,14 +12755,11 @@ dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
 
        if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
-                                        aminfo->dobj.name,
-                                        NULL,
-                                        NULL,
-                                        "",
-                                        false, "ACCESS METHOD", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = aminfo->dobj.name,
+                                                                 .description = "ACCESS METHOD",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Access Method Comments */
        if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13019,14 +13118,13 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 
        if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
-                                        opcinfo->dobj.name,
-                                        opcinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        opcinfo->rolname,
-                                        false, "OPERATOR CLASS", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
+                                                                 .namespace = opcinfo->dobj.namespace->dobj.name,
+                                                                 .owner = opcinfo->rolname,
+                                                                 .description = "OPERATOR CLASS",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Operator Class Comments */
        if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13286,14 +13384,13 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 
        if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
-                                        opfinfo->dobj.name,
-                                        opfinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        opfinfo->rolname,
-                                        false, "OPERATOR FAMILY", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
+                                                                 .namespace = opfinfo->dobj.namespace->dobj.name,
+                                                                 .owner = opfinfo->rolname,
+                                                                 .description = "OPERATOR FAMILY",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Operator Family Comments */
        if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13324,6 +13421,7 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
        char       *qcollname;
        PGresult   *res;
        int                     i_collprovider;
+       int                     i_collisdeterministic;
        int                     i_collcollate;
        int                     i_collctype;
        const char *collprovider;
@@ -13341,28 +13439,35 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
        qcollname = pg_strdup(fmtId(collinfo->dobj.name));
 
        /* Get collation-specific details */
+       appendPQExpBufferStr(query, "SELECT ");
+
        if (fout->remoteVersion >= 100000)
-               appendPQExpBuffer(query, "SELECT "
-                                                 "collprovider, "
-                                                 "collcollate, "
-                                                 "collctype, "
-                                                 "collversion "
-                                                 "FROM pg_catalog.pg_collation c "
-                                                 "WHERE c.oid = '%u'::pg_catalog.oid",
-                                                 collinfo->dobj.catId.oid);
+               appendPQExpBufferStr(query,
+                                                        "collprovider, "
+                                                        "collversion, ");
        else
-               appendPQExpBuffer(query, "SELECT "
-                                                 "'c' AS collprovider, "
-                                                 "collcollate, "
-                                                 "collctype, "
-                                                 "NULL AS collversion "
-                                                 "FROM pg_catalog.pg_collation c "
-                                                 "WHERE c.oid = '%u'::pg_catalog.oid",
-                                                 collinfo->dobj.catId.oid);
+               appendPQExpBufferStr(query,
+                                                        "'c' AS collprovider, "
+                                                        "NULL AS collversion, ");
+
+       if (fout->remoteVersion >= 120000)
+               appendPQExpBufferStr(query,
+                                                        "collisdeterministic, ");
+       else
+               appendPQExpBufferStr(query,
+                                                        "true AS collisdeterministic, ");
+
+       appendPQExpBuffer(query,
+                                         "collcollate, "
+                                         "collctype "
+                                         "FROM pg_catalog.pg_collation c "
+                                         "WHERE c.oid = '%u'::pg_catalog.oid",
+                                         collinfo->dobj.catId.oid);
 
        res = ExecuteSqlQueryForSingleRow(fout, query->data);
 
        i_collprovider = PQfnumber(res, "collprovider");
+       i_collisdeterministic = PQfnumber(res, "collisdeterministic");
        i_collcollate = PQfnumber(res, "collcollate");
        i_collctype = PQfnumber(res, "collctype");
 
@@ -13385,9 +13490,11 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
                /* to allow dumping pg_catalog; not accepted on input */
                appendPQExpBufferStr(q, "default");
        else
-               exit_horribly(NULL,
-                                         "unrecognized collation provider: %s\n",
-                                         collprovider);
+               fatal("unrecognized collation provider: %s",
+                         collprovider);
+
+       if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
+               appendPQExpBufferStr(q, ", deterministic = false");
 
        if (strcmp(collcollate, collctype) == 0)
        {
@@ -13429,14 +13536,13 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 
        if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
-                                        collinfo->dobj.name,
-                                        collinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        collinfo->rolname,
-                                        false, "COLLATION", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = collinfo->dobj.name,
+                                                                 .namespace = collinfo->dobj.namespace->dobj.name,
+                                                                 .owner = collinfo->rolname,
+                                                                 .description = "COLLATION",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Collation Comments */
        if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13524,14 +13630,13 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
 
        if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
-                                        convinfo->dobj.name,
-                                        convinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        convinfo->rolname,
-                                        false, "CONVERSION", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = convinfo->dobj.name,
+                                                                 .namespace = convinfo->dobj.namespace->dobj.name,
+                                                                 .owner = convinfo->rolname,
+                                                                 .description = "CONVERSION",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Conversion Comments */
        if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -13566,7 +13671,7 @@ format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
                appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
 
        if (agginfo->aggfn.nargs == 0)
-               appendPQExpBuffer(&buf, "(*)");
+               appendPQExpBufferStr(&buf, "(*)");
        else
        {
                appendPQExpBufferChar(&buf, '(');
@@ -13857,8 +13962,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 
        if (!convertok)
        {
-               write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
-                                 aggsig);
+               pg_log_warning("aggregate function %s could not be dumped correctly for this database version; ignored",
+                                          aggsig);
 
                if (aggfullsig)
                        free(aggfullsig);
@@ -13912,8 +14017,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
                                        appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
                                        break;
                                default:
-                                       exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
-                                                                 agginfo->aggfn.dobj.name);
+                                       fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
+                                                 agginfo->aggfn.dobj.name);
                                        break;
                        }
                }
@@ -13968,8 +14073,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
                                        appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
                                        break;
                                default:
-                                       exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
-                                                                 agginfo->aggfn.dobj.name);
+                                       fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
+                                                 agginfo->aggfn.dobj.name);
                                        break;
                        }
                }
@@ -13993,8 +14098,8 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
                else if (proparallel[0] == PROPARALLEL_RESTRICTED)
                        appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
                else if (proparallel[0] != PROPARALLEL_UNSAFE)
-                       exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
-                                                 agginfo->aggfn.dobj.name);
+                       fatal("unrecognized proparallel value for function \"%s\"",
+                                 agginfo->aggfn.dobj.name);
        }
 
        appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
@@ -14013,14 +14118,13 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
        if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
                                         agginfo->aggfn.dobj.dumpId,
-                                        aggsig_tag,
-                                        agginfo->aggfn.dobj.namespace->dobj.name,
-                                        NULL,
-                                        agginfo->aggfn.rolname,
-                                        false, "AGGREGATE", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = aggsig_tag,
+                                                                 .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
+                                                                 .owner = agginfo->aggfn.rolname,
+                                                                 .description = "AGGREGATE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Aggregate Comments */
        if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -14111,14 +14215,12 @@ dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 
        if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
-                                        prsinfo->dobj.name,
-                                        prsinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        "",
-                                        false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
+                                                                 .namespace = prsinfo->dobj.namespace->dobj.name,
+                                                                 .description = "TEXT SEARCH PARSER",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Parser Comments */
        if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -14191,14 +14293,13 @@ dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 
        if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
-                                        dictinfo->dobj.name,
-                                        dictinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        dictinfo->rolname,
-                                        false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
+                                                                 .namespace = dictinfo->dobj.namespace->dobj.name,
+                                                                 .owner = dictinfo->rolname,
+                                                                 .description = "TEXT SEARCH DICTIONARY",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Dictionary Comments */
        if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -14252,14 +14353,12 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 
        if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
-                                        tmplinfo->dobj.name,
-                                        tmplinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        "",
-                                        false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
+                                                                 .namespace = tmplinfo->dobj.namespace->dobj.name,
+                                                                 .description = "TEXT SEARCH TEMPLATE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Template Comments */
        if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -14372,14 +14471,13 @@ dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 
        if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
-                                        cfginfo->dobj.name,
-                                        cfginfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        cfginfo->rolname,
-                                        false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
+                                                                 .namespace = cfginfo->dobj.namespace->dobj.name,
+                                                                 .owner = cfginfo->rolname,
+                                                                 .description = "TEXT SEARCH CONFIGURATION",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Configuration Comments */
        if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -14438,14 +14536,12 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 
        if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
-                                        fdwinfo->dobj.name,
-                                        NULL,
-                                        NULL,
-                                        fdwinfo->rolname,
-                                        false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
+                                                                 .owner = fdwinfo->rolname,
+                                                                 .description = "FOREIGN DATA WRAPPER",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Foreign Data Wrapper Comments */
        if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -14529,14 +14625,12 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 
        if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
-                                        srvinfo->dobj.name,
-                                        NULL,
-                                        NULL,
-                                        srvinfo->rolname,
-                                        false, "SERVER", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
+                                                                 .owner = srvinfo->rolname,
+                                                                 .description = "SERVER",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Foreign Server Comments */
        if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -14647,14 +14741,13 @@ dumpUserMappings(Archive *fout,
                                                  usename, servername);
 
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        tag->data,
-                                        namespace,
-                                        NULL,
-                                        owner, false,
-                                        "USER MAPPING", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        &dumpId, 1,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag->data,
+                                                                 .namespace = namespace,
+                                                                 .owner = owner,
+                                                                 .description = "USER MAPPING",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
        }
 
        PQclear(res);
@@ -14702,9 +14795,8 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
                        break;
                default:
                        /* shouldn't get here */
-                       exit_horribly(NULL,
-                                                 "unrecognized object type in default privileges: %d\n",
-                                                 (int) daclinfo->defaclobjtype);
+                       fatal("unrecognized object type in default privileges: %d",
+                                 (int) daclinfo->defaclobjtype);
                        type = "";                      /* keep compiler quiet */
        }
 
@@ -14721,19 +14813,18 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
                                                                 daclinfo->defaclrole,
                                                                 fout->remoteVersion,
                                                                 q))
-               exit_horribly(NULL, "could not parse default ACL list (%s)\n",
-                                         daclinfo->defaclacl);
+               fatal("could not parse default ACL list (%s)",
+                         daclinfo->defaclacl);
 
        if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
                ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
-                                        tag->data,
-                                        daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
-                                        NULL,
-                                        daclinfo->defaclrole,
-                                        false, "DEFAULT ACL", SECTION_POST_DATA,
-                                        q->data, "", NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag->data,
+                                                                 .namespace = daclinfo->dobj.namespace ?
+                                                                 daclinfo->dobj.namespace->dobj.name : NULL,
+                                                                 .owner = daclinfo->defaclrole,
+                                                                 .description = "DEFAULT ACL",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = q->data));
 
        destroyPQExpBuffer(tag);
        destroyPQExpBuffer(q);
@@ -14798,22 +14889,20 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
         */
        if (strlen(initacls) != 0 || strlen(initracls) != 0)
        {
-               appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
+               appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
                if (!buildACLCommands(name, subname, nspname, type,
                                                          initacls, initracls, owner,
                                                          "", fout->remoteVersion, sql))
-                       exit_horribly(NULL,
-                                                 "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
-                                                 initacls, initracls, name, type);
-               appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
+                       fatal("could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)",
+                                 initacls, initracls, name, type);
+               appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
        }
 
        if (!buildACLCommands(name, subname, nspname, type,
                                                  acls, racls, owner,
                                                  "", fout->remoteVersion, sql))
-               exit_horribly(NULL,
-                                         "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
-                                         acls, racls, name, type);
+               fatal("could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)",
+                         acls, racls, name, type);
 
        if (sql->len > 0)
        {
@@ -14825,13 +14914,14 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
                        appendPQExpBuffer(tag, "%s %s", type, name);
 
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        tag->data, nspname,
-                                        NULL,
-                                        owner ? owner : "",
-                                        false, "ACL", SECTION_NONE,
-                                        sql->data, "", NULL,
-                                        &(objDumpId), 1,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag->data,
+                                                                 .namespace = nspname,
+                                                                 .owner = owner,
+                                                                 .description = "ACL",
+                                                                 .section = SECTION_NONE,
+                                                                 .createStmt = sql->data,
+                                                                 .deps = &objDumpId,
+                                                                 .nDeps = 1));
                destroyPQExpBuffer(tag);
        }
 
@@ -14913,11 +15003,14 @@ dumpSecLabel(Archive *fout, const char *type, const char *name,
 
                appendPQExpBuffer(tag, "%s %s", type, name);
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        tag->data, namespace, NULL, owner,
-                                        false, "SECURITY LABEL", SECTION_NONE,
-                                        query->data, "", NULL,
-                                        &(dumpId), 1,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag->data,
+                                                                 .namespace = namespace,
+                                                                 .owner = owner,
+                                                                 .description = "SECURITY LABEL",
+                                                                 .section = SECTION_NONE,
+                                                                 .createStmt = query->data,
+                                                                 .deps = &dumpId,
+                                                                 .nDeps = 1));
                destroyPQExpBuffer(tag);
        }
 
@@ -14993,13 +15086,14 @@ dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
                appendPQExpBuffer(target, "%s %s", reltypename,
                                                  fmtId(tbinfo->dobj.name));
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        target->data,
-                                        tbinfo->dobj.namespace->dobj.name,
-                                        NULL, tbinfo->rolname,
-                                        false, "SECURITY LABEL", SECTION_NONE,
-                                        query->data, "", NULL,
-                                        &(tbinfo->dobj.dumpId), 1,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = target->data,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "SECURITY LABEL",
+                                                                 .section = SECTION_NONE,
+                                                                 .createStmt = query->data,
+                                                                 .deps = &(tbinfo->dobj.dumpId),
+                                                                 .nDeps = 1));
        }
        destroyPQExpBuffer(query);
        destroyPQExpBuffer(target);
@@ -15306,18 +15400,18 @@ createViewAsClause(Archive *fout, TableInfo *tbinfo)
        if (PQntuples(res) != 1)
        {
                if (PQntuples(res) < 1)
-                       exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
-                                                 tbinfo->dobj.name);
+                       fatal("query to obtain definition of view \"%s\" returned no data",
+                                 tbinfo->dobj.name);
                else
-                       exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
-                                                 tbinfo->dobj.name);
+                       fatal("query to obtain definition of view \"%s\" returned more than one definition",
+                                 tbinfo->dobj.name);
        }
 
        len = PQgetlength(res, 0, 0);
 
        if (len == 0)
-               exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
-                                         tbinfo->dobj.name);
+               fatal("definition of view \"%s\" appears to be empty (length zero)",
+                         tbinfo->dobj.name);
 
        /* Strip off the trailing semicolon so that other things may follow. */
        Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
@@ -15390,14 +15484,17 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
        int                     actual_atts;    /* number of attrs in this CREATE statement */
        const char *reltypename;
        char       *storage;
-       char       *srvname;
-       char       *ftoptions;
        int                     j,
                                k;
 
        qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
        qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
 
+
+       if (tbinfo->hasoids)
+               pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
+                                          qrelname);
+
        if (dopt->binary_upgrade)
                binary_upgrade_set_type_oids_by_rel_oid(fout, q,
                                                                                                tbinfo->dobj.catId.oid);
@@ -15442,6 +15539,9 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
        }
        else
        {
+               char       *ftoptions = NULL;
+               char       *srvname = NULL;
+
                switch (tbinfo->relkind)
                {
                        case RELKIND_FOREIGN_TABLE:
@@ -15478,13 +15578,9 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                }
                        case RELKIND_MATVIEW:
                                reltypename = "MATERIALIZED VIEW";
-                               srvname = NULL;
-                               ftoptions = NULL;
                                break;
                        default:
                                reltypename = "TABLE";
-                               srvname = NULL;
-                               ftoptions = NULL;
                }
 
                numParents = tbinfo->numParents;
@@ -15509,27 +15605,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                if (tbinfo->reloftype && !dopt->binary_upgrade)
                        appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
 
-               /*
-                * If the table is a partition, dump it as such; except in the case of
-                * a binary upgrade, we dump the table normally and attach it to the
-                * parent afterward.
-                */
-               if (tbinfo->ispartition && !dopt->binary_upgrade)
-               {
-                       TableInfo  *parentRel = tbinfo->parents[0];
-
-                       /*
-                        * With partitions, unlike inheritance, there can only be one
-                        * parent.
-                        */
-                       if (tbinfo->numParents != 1)
-                               exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
-                                                         tbinfo->numParents, tbinfo->dobj.name);
-
-                       appendPQExpBuffer(q, " PARTITION OF %s",
-                                                         fmtQualifiedDumpable(parentRel));
-               }
-
                if (tbinfo->relkind != RELKIND_MATVIEW)
                {
                        /* Dump the attributes */
@@ -15544,26 +15619,30 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                 */
                                if (shouldPrintColumn(dopt, tbinfo, j))
                                {
+                                       bool            print_default;
+                                       bool            print_notnull;
+
                                        /*
                                         * Default value --- suppress if to be printed separately.
                                         */
-                                       bool            has_default = (tbinfo->attrdefs[j] != NULL &&
-                                                                                          !tbinfo->attrdefs[j]->separate);
+                                       print_default = (tbinfo->attrdefs[j] != NULL &&
+                                                                        !tbinfo->attrdefs[j]->separate);
 
                                        /*
                                         * Not Null constraint --- suppress if inherited, except
-                                        * in binary-upgrade case where that won't work.
+                                        * if partition, or in binary-upgrade case where that
+                                        * won't work.
                                         */
-                                       bool            has_notnull = (tbinfo->notnull[j] &&
-                                                                                          (!tbinfo->inhNotNull[j] ||
-                                                                                               dopt->binary_upgrade));
+                                       print_notnull = (tbinfo->notnull[j] &&
+                                                                        (!tbinfo->inhNotNull[j] ||
+                                                                         tbinfo->ispartition || dopt->binary_upgrade));
 
                                        /*
-                                        * Skip column if fully defined by reloftype or the
-                                        * partition parent.
+                                        * Skip column if fully defined by reloftype, except in
+                                        * binary upgrade
                                         */
-                                       if ((tbinfo->reloftype || tbinfo->ispartition) &&
-                                               !has_default && !has_notnull && !dopt->binary_upgrade)
+                                       if (tbinfo->reloftype && !print_default && !print_notnull &&
+                                               !dopt->binary_upgrade)
                                                continue;
 
                                        /* Format properly if not first attr */
@@ -15586,25 +15665,35 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                                 * clean things up later.
                                                 */
                                                appendPQExpBufferStr(q, " INTEGER /* dummy */");
-                                               /* Skip all the rest, too */
+                                               /* and skip to the next column */
                                                continue;
                                        }
 
                                        /*
-                                        * Attribute type
-                                        *
-                                        * In binary-upgrade mode, we always include the type. If
-                                        * we aren't in binary-upgrade mode, then we skip the type
-                                        * when creating a typed table ('OF type_name') or a
-                                        * partition ('PARTITION OF'), since the type comes from
-                                        * the parent/partitioned table.
+                                        * Attribute type; print it except when creating a typed
+                                        * table ('OF type_name'), but in binary-upgrade mode,
+                                        * print it in that case too.
                                         */
-                                       if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
+                                       if (dopt->binary_upgrade || !tbinfo->reloftype)
                                        {
                                                appendPQExpBuffer(q, " %s",
                                                                                  tbinfo->atttypnames[j]);
                                        }
 
+                                       if (print_default)
+                                       {
+                                               if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
+                                                       appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
+                                                                                         tbinfo->attrdefs[j]->adef_expr);
+                                               else
+                                                       appendPQExpBuffer(q, " DEFAULT %s",
+                                                                                         tbinfo->attrdefs[j]->adef_expr);
+                                       }
+
+
+                                       if (print_notnull)
+                                               appendPQExpBufferStr(q, " NOT NULL");
+
                                        /* Add collation if not default for the type */
                                        if (OidIsValid(tbinfo->attcollation[j]))
                                        {
@@ -15615,24 +15704,23 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                                        appendPQExpBuffer(q, " COLLATE %s",
                                                                                          fmtQualifiedDumpable(coll));
                                        }
-
-                                       if (has_default)
-                                               appendPQExpBuffer(q, " DEFAULT %s",
-                                                                                 tbinfo->attrdefs[j]->adef_expr);
-
-                                       if (has_notnull)
-                                               appendPQExpBufferStr(q, " NOT NULL");
                                }
                        }
 
                        /*
                         * Add non-inherited CHECK constraints, if any.
+                        *
+                        * For partitions, we need to include check constraints even if
+                        * they're not defined locally, because the ALTER TABLE ATTACH
+                        * PARTITION that we'll emit later expects the constraint to be
+                        * there.  (No need to fix conislocal: ATTACH PARTITION does that)
                         */
                        for (j = 0; j < tbinfo->ncheck; j++)
                        {
                                ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
 
-                               if (constr->separate || !constr->conislocal)
+                               if (constr->separate ||
+                                       (!constr->conislocal && !tbinfo->ispartition))
                                        continue;
 
                                if (actual_atts == 0)
@@ -15649,25 +15737,20 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 
                        if (actual_atts)
                                appendPQExpBufferStr(q, "\n)");
-                       else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
-                                          !dopt->binary_upgrade))
+                       else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
                        {
                                /*
-                                * We must have a parenthesized attribute list, even though
-                                * empty, when not using the OF TYPE or PARTITION OF syntax.
+                                * No attributes? we must have a parenthesized attribute list,
+                                * even though empty, when not using the OF TYPE syntax.
                                 */
                                appendPQExpBufferStr(q, " (\n)");
                        }
 
-                       if (tbinfo->ispartition && !dopt->binary_upgrade)
-                       {
-                               appendPQExpBufferChar(q, '\n');
-                               appendPQExpBufferStr(q, tbinfo->partbound);
-                       }
-
-                       /* Emit the INHERITS clause, except if this is a partition. */
-                       if (numParents > 0 &&
-                               !tbinfo->ispartition &&
+                       /*
+                        * Emit the INHERITS clause (not for partitions), except in
+                        * binary-upgrade mode.
+                        */
+                       if (numParents > 0 && !tbinfo->ispartition &&
                                !dopt->binary_upgrade)
                        {
                                appendPQExpBufferStr(q, "\nINHERITS (");
@@ -15818,11 +15901,17 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                }
                        }
 
+                       /*
+                        * Add inherited CHECK constraints, if any.
+                        *
+                        * For partitions, they were already dumped, and conislocal
+                        * doesn't need fixing.
+                        */
                        for (k = 0; k < tbinfo->ncheck; k++)
                        {
                                ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
 
-                               if (constr->separate || constr->conislocal)
+                               if (constr->separate || constr->conislocal || tbinfo->ispartition)
                                        continue;
 
                                appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
@@ -15840,30 +15929,16 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
                        }
 
-                       if (numParents > 0)
+                       if (numParents > 0 && !tbinfo->ispartition)
                        {
-                               appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
+                               appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
                                for (k = 0; k < numParents; k++)
                                {
                                        TableInfo  *parentRel = parents[k];
 
-                                       /* In the partitioning case, we alter the parent */
-                                       if (tbinfo->ispartition)
-                                               appendPQExpBuffer(q,
-                                                                                 "ALTER TABLE ONLY %s ATTACH PARTITION ",
-                                                                                 fmtQualifiedDumpable(parentRel));
-                                       else
-                                               appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
-                                                                                 qualrelname);
-
-                                       /* Partition needs specifying the bounds */
-                                       if (tbinfo->ispartition)
-                                               appendPQExpBuffer(q, "%s %s;\n",
-                                                                                 qualrelname,
-                                                                                 tbinfo->partbound);
-                                       else
-                                               appendPQExpBuffer(q, "%s;\n",
-                                                                                 fmtQualifiedDumpable(parentRel));
+                                       appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT %s;\n",
+                                                                         qualrelname,
+                                                                         fmtQualifiedDumpable(parentRel));
                                }
                        }
 
@@ -15876,6 +15951,27 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                        }
                }
 
+               /*
+                * For partitioned tables, emit the ATTACH PARTITION clause.  Note
+                * that we always want to create partitions this way instead of using
+                * CREATE TABLE .. PARTITION OF, mainly to preserve a possible column
+                * layout discrepancy with the parent, but also to ensure it gets the
+                * correct tablespace setting if it differs from the parent's.
+                */
+               if (tbinfo->ispartition)
+               {
+                       /* With partitions there can only be one parent */
+                       if (tbinfo->numParents != 1)
+                               fatal("invalid number of parents %d for table \"%s\"",
+                                         tbinfo->numParents, tbinfo->dobj.name);
+
+                       /* Perform ALTER TABLE on the parent */
+                       appendPQExpBuffer(q,
+                                                         "ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
+                                                         fmtQualifiedDumpable(parents[0]),
+                                                         qualrelname, tbinfo->partbound);
+               }
+
                /*
                 * In binary_upgrade mode, arrange to restore the old relfrozenxid and
                 * relminmxid of all vacuumable relations.  (While vacuum.c processes
@@ -16008,7 +16104,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                        /*
                         * Dump per-column attributes.
                         */
-                       if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
+                       if (tbinfo->attoptions[j][0] != '\0')
                        {
                                appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
                                                                  qualrelname);
@@ -16022,7 +16118,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                         * Dump per-column fdw options.
                         */
                        if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
-                               tbinfo->attfdwoptions[j] &&
                                tbinfo->attfdwoptions[j][0] != '\0')
                        {
                                appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
@@ -16033,6 +16128,11 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                                                  tbinfo->attfdwoptions[j]);
                        }
                }
+
+               if (ftoptions)
+                       free(ftoptions);
+               if (srvname)
+                       free(srvname);
        }
 
        /*
@@ -16059,10 +16159,6 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                }
        }
 
-       if (tbinfo->relkind == RELKIND_FOREIGN_TABLE && tbinfo->hasoids)
-               appendPQExpBuffer(q, "\nALTER TABLE ONLY %s SET WITH OIDS;\n",
-                                                 qualrelname);
-
        if (tbinfo->forcerowsec)
                appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
                                                  qualrelname);
@@ -16073,19 +16169,26 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                                                                                tbinfo->dobj.namespace->dobj.name);
 
        if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
-               ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-                                        tbinfo->dobj.name,
-                                        tbinfo->dobj.namespace->dobj.name,
-                                        (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
-                                        tbinfo->rolname,
-                                        (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
-                                        reltypename,
-                                        tbinfo->postponed_def ?
-                                        SECTION_POST_DATA : SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+       {
+               char       *tableam = NULL;
+
+               if (tbinfo->relkind == RELKIND_RELATION ||
+                       tbinfo->relkind == RELKIND_MATVIEW)
+                       tableam = tbinfo->amname;
 
+               ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
+                                        ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
+                                                                 NULL : tbinfo->reltablespace,
+                                                                 .tableam = tableam,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = reltypename,
+                                                                 .section = tbinfo->postponed_def ?
+                                                                 SECTION_POST_DATA : SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
+       }
 
        /* Dump Table Comments */
        if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -16155,14 +16258,13 @@ dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 
        if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
-                                        tag,
-                                        tbinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tbinfo->rolname,
-                                        false, "DEFAULT", SECTION_PRE_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "DEFAULT",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        free(tag);
        destroyPQExpBuffer(q);
@@ -16186,8 +16288,6 @@ getAttrName(int attrnum, TableInfo *tblInfo)
        {
                case SelfItemPointerAttributeNumber:
                        return "ctid";
-               case ObjectIdAttributeNumber:
-                       return "oid";
                case MinTransactionIdAttributeNumber:
                        return "xmin";
                case MinCommandIdAttributeNumber:
@@ -16199,8 +16299,8 @@ getAttrName(int attrnum, TableInfo *tblInfo)
                case TableOidAttributeNumber:
                        return "tableoid";
        }
-       exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
-                                 attrnum, tblInfo->dobj.name);
+       fatal("invalid column number %d for table \"%s\"",
+                 attrnum, tblInfo->dobj.name);
        return NULL;                            /* keep compiler quiet */
 }
 
@@ -16235,6 +16335,13 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
         */
        if (!is_constraint)
        {
+               char       *indstatcols = indxinfo->indstatcols;
+               char       *indstatvals = indxinfo->indstatvals;
+               char      **indstatcolsarray = NULL;
+               char      **indstatvalsarray = NULL;
+               int                     nstatcols;
+               int                     nstatvals;
+
                if (dopt->binary_upgrade)
                        binary_upgrade_set_pg_class_oids(fout, q,
                                                                                         indxinfo->dobj.catId.oid, true);
@@ -16258,6 +16365,32 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
                                                          qindxname);
                }
 
+               /*
+                * If the index has any statistics on some of its columns, generate
+                * the associated ALTER INDEX queries.
+                */
+               if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
+                       parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
+                       nstatcols == nstatvals)
+               {
+                       int                     j;
+
+                       for (j = 0; j < nstatcols; j++)
+                       {
+                               appendPQExpBuffer(q, "ALTER INDEX %s ",
+                                                                 fmtQualifiedDumpable(indxinfo));
+
+                               /*
+                                * Note that this is a column number, so no quotes should be
+                                * used.
+                                */
+                               appendPQExpBuffer(q, "ALTER COLUMN %s ",
+                                                                 indstatcolsarray[j]);
+                               appendPQExpBuffer(q, "SET STATISTICS %s;\n",
+                                                                 indstatvalsarray[j]);
+                       }
+               }
+
                /* If the index defines identity, we need to record that. */
                if (indxinfo->indisreplident)
                {
@@ -16273,14 +16406,19 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
 
                if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                        ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
-                                                indxinfo->dobj.name,
-                                                tbinfo->dobj.namespace->dobj.name,
-                                                indxinfo->tablespace,
-                                                tbinfo->rolname, false,
-                                                "INDEX", SECTION_POST_DATA,
-                                                q->data, delq->data, NULL,
-                                                NULL, 0,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
+                                                                         .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                         .tablespace = indxinfo->tablespace,
+                                                                         .owner = tbinfo->rolname,
+                                                                         .description = "INDEX",
+                                                                         .section = SECTION_POST_DATA,
+                                                                         .createStmt = q->data,
+                                                                         .dropStmt = delq->data));
+
+               if (indstatcolsarray)
+                       free(indstatcolsarray);
+               if (indstatvalsarray)
+                       free(indstatvalsarray);
        }
 
        /* Dump Index Comments */
@@ -16311,19 +16449,17 @@ dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
        {
                PQExpBuffer q = createPQExpBuffer();
 
-               appendPQExpBuffer(q, "\nALTER INDEX %s ",
+               appendPQExpBuffer(q, "ALTER INDEX %s ",
                                                  fmtQualifiedDumpable(attachinfo->parentIdx));
                appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
                                                  fmtQualifiedDumpable(attachinfo->partitionIdx));
 
                ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
-                                        attachinfo->dobj.name,
-                                        NULL, NULL,
-                                        "",
-                                        false, "INDEX ATTACH", SECTION_POST_DATA,
-                                        q->data, "", NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
+                                                                 .namespace = attachinfo->dobj.namespace->dobj.name,
+                                                                 .description = "INDEX ATTACH",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = q->data));
 
                destroyPQExpBuffer(q);
        }
@@ -16371,14 +16507,13 @@ dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
        if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, statsextinfo->dobj.catId,
                                         statsextinfo->dobj.dumpId,
-                                        statsextinfo->dobj.name,
-                                        statsextinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        statsextinfo->rolname, false,
-                                        "STATISTICS", SECTION_POST_DATA,
-                                        q->data, delq->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
+                                                                 .namespace = statsextinfo->dobj.namespace->dobj.name,
+                                                                 .owner = statsextinfo->rolname,
+                                                                 .description = "STATISTICS",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = q->data,
+                                                                 .dropStmt = delq->data));
 
        /* Dump Statistics Comments */
        if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -16426,8 +16561,8 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
                indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
 
                if (indxinfo == NULL)
-                       exit_horribly(NULL, "missing index for constraint \"%s\"\n",
-                                                 coninfo->dobj.name);
+                       fatal("missing index for constraint \"%s\"",
+                                 coninfo->dobj.name);
 
                if (dopt->binary_upgrade)
                        binary_upgrade_set_pg_class_oids(fout, q,
@@ -16462,7 +16597,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
                        }
 
                        if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
-                               appendPQExpBuffer(q, ") INCLUDE (");
+                               appendPQExpBufferStr(q, ") INCLUDE (");
 
                        for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
                        {
@@ -16532,14 +16667,14 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
                if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                        ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-                                                tag,
-                                                tbinfo->dobj.namespace->dobj.name,
-                                                indxinfo->tablespace,
-                                                tbinfo->rolname, false,
-                                                "CONSTRAINT", SECTION_POST_DATA,
-                                                q->data, delq->data, NULL,
-                                                NULL, 0,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = tag,
+                                                                         .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                         .tablespace = indxinfo->tablespace,
+                                                                         .owner = tbinfo->rolname,
+                                                                         .description = "CONSTRAINT",
+                                                                         .section = SECTION_POST_DATA,
+                                                                         .createStmt = q->data,
+                                                                         .dropStmt = delq->data));
        }
        else if (coninfo->contype == 'f')
        {
@@ -16572,14 +16707,13 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
                if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                        ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-                                                tag,
-                                                tbinfo->dobj.namespace->dobj.name,
-                                                NULL,
-                                                tbinfo->rolname, false,
-                                                "FK CONSTRAINT", SECTION_POST_DATA,
-                                                q->data, delq->data, NULL,
-                                                NULL, 0,
-                                                NULL, NULL);
+                                                ARCHIVE_OPTS(.tag = tag,
+                                                                         .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                         .owner = tbinfo->rolname,
+                                                                         .description = "FK CONSTRAINT",
+                                                                         .section = SECTION_POST_DATA,
+                                                                         .createStmt = q->data,
+                                                                         .dropStmt = delq->data));
        }
        else if (coninfo->contype == 'c' && tbinfo)
        {
@@ -16604,14 +16738,13 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
                        if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                                ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-                                                        tag,
-                                                        tbinfo->dobj.namespace->dobj.name,
-                                                        NULL,
-                                                        tbinfo->rolname, false,
-                                                        "CHECK CONSTRAINT", SECTION_POST_DATA,
-                                                        q->data, delq->data, NULL,
-                                                        NULL, 0,
-                                                        NULL, NULL);
+                                                        ARCHIVE_OPTS(.tag = tag,
+                                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                                 .owner = tbinfo->rolname,
+                                                                                 .description = "CHECK CONSTRAINT",
+                                                                                 .section = SECTION_POST_DATA,
+                                                                                 .createStmt = q->data,
+                                                                                 .dropStmt = delq->data));
                }
        }
        else if (coninfo->contype == 'c' && tbinfo == NULL)
@@ -16637,20 +16770,19 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
                        if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                                ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
-                                                        tag,
-                                                        tyinfo->dobj.namespace->dobj.name,
-                                                        NULL,
-                                                        tyinfo->rolname, false,
-                                                        "CHECK CONSTRAINT", SECTION_POST_DATA,
-                                                        q->data, delq->data, NULL,
-                                                        NULL, 0,
-                                                        NULL, NULL);
+                                                        ARCHIVE_OPTS(.tag = tag,
+                                                                                 .namespace = tyinfo->dobj.namespace->dobj.name,
+                                                                                 .owner = tyinfo->rolname,
+                                                                                 .description = "CHECK CONSTRAINT",
+                                                                                 .section = SECTION_POST_DATA,
+                                                                                 .createStmt = q->data,
+                                                                                 .dropStmt = delq->data));
                }
        }
        else
        {
-               exit_horribly(NULL, "unrecognized constraint type: %c\n",
-                                         coninfo->contype);
+               fatal("unrecognized constraint type: %c",
+                         coninfo->contype);
        }
 
        /* Dump Constraint Comments --- only works for table constraints */
@@ -16781,10 +16913,10 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 
        if (PQntuples(res) != 1)
        {
-               write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
-                                                                "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
-                                                                PQntuples(res)),
-                                 tbinfo->dobj.name, PQntuples(res));
+               pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
+                                                         "query to get data of sequence \"%s\" returned %d rows (expected 1)",
+                                                         PQntuples(res)),
+                                        tbinfo->dobj.name, PQntuples(res));
                exit_nicely(1);
        }
 
@@ -16815,7 +16947,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
        }
        else
        {
-               exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
+               fatal("unrecognized sequence type: %s", seqtype);
                default_minv = default_maxv = 0;        /* keep compiler quiet */
        }
 
@@ -16862,9 +16994,9 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                                                  "ALTER COLUMN %s ADD GENERATED ",
                                                  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
                if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
-                       appendPQExpBuffer(query, "ALWAYS");
+                       appendPQExpBufferStr(query, "ALWAYS");
                else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
-                       appendPQExpBuffer(query, "BY DEFAULT");
+                       appendPQExpBufferStr(query, "BY DEFAULT");
                appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
                                                  fmtQualifiedDumpable(tbinfo));
        }
@@ -16911,14 +17043,13 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 
        if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
-                                        tbinfo->dobj.name,
-                                        tbinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tbinfo->rolname,
-                                        false, "SEQUENCE", SECTION_PRE_DATA,
-                                        query->data, delqry->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "SEQUENCE",
+                                                                 .section = SECTION_PRE_DATA,
+                                                                 .createStmt = query->data,
+                                                                 .dropStmt = delqry->data));
 
        /*
         * If the sequence is owned by a table column, emit the ALTER for it as a
@@ -16937,8 +17068,8 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
 
                if (owning_tab == NULL)
-                       exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
-                                                 tbinfo->owning_tab, tbinfo->dobj.catId.oid);
+                       fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
+                                 tbinfo->owning_tab, tbinfo->dobj.catId.oid);
 
                if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
                {
@@ -16952,14 +17083,14 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 
                        if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                                        tbinfo->dobj.name,
-                                                        tbinfo->dobj.namespace->dobj.name,
-                                                        NULL,
-                                                        tbinfo->rolname,
-                                                        false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
-                                                        query->data, "", NULL,
-                                                        &(tbinfo->dobj.dumpId), 1,
-                                                        NULL, NULL);
+                                                        ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
+                                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                                 .owner = tbinfo->rolname,
+                                                                                 .description = "SEQUENCE OWNED BY",
+                                                                                 .section = SECTION_PRE_DATA,
+                                                                                 .createStmt = query->data,
+                                                                                 .deps = &(tbinfo->dobj.dumpId),
+                                                                                 .nDeps = 1));
                }
        }
 
@@ -17002,10 +17133,10 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 
        if (PQntuples(res) != 1)
        {
-               write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
-                                                                "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
-                                                                PQntuples(res)),
-                                 tbinfo->dobj.name, PQntuples(res));
+               pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
+                                                         "query to get data of sequence \"%s\" returned %d rows (expected 1)",
+                                                         PQntuples(res)),
+                                        tbinfo->dobj.name, PQntuples(res));
                exit_nicely(1);
        }
 
@@ -17020,14 +17151,14 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 
        if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
-                                        tbinfo->dobj.name,
-                                        tbinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tbinfo->rolname,
-                                        false, "SEQUENCE SET", SECTION_DATA,
-                                        query->data, "", NULL,
-                                        &(tbinfo->dobj.dumpId), 1,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "SEQUENCE SET",
+                                                                 .section = SECTION_DATA,
+                                                                 .createStmt = query->data,
+                                                                 .deps = &(tbinfo->dobj.dumpId),
+                                                                 .nDeps = 1));
 
        PQclear(res);
 
@@ -17098,7 +17229,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
                        appendPQExpBufferStr(query, "INSTEAD OF");
                else
                {
-                       write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
+                       pg_log_error("unexpected tgtype value: %d", tginfo->tgtype);
                        exit_nicely(1);
                }
 
@@ -17158,7 +17289,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
                        appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
 
                /* regproc output is already sufficiently quoted */
-               appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
+               appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
                                                  tginfo->tgfname);
 
                tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
@@ -17172,10 +17303,10 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
                        if (p + tlen >= tgargs + lentgargs)
                        {
                                /* hm, not found before end of bytea value... */
-                               write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
-                                                 tginfo->tgargs,
-                                                 tginfo->dobj.name,
-                                                 tbinfo->dobj.name);
+                               pg_log_error("invalid argument string (%s) for trigger \"%s\" on table \"%s\"",
+                                                        tginfo->tgargs,
+                                                        tginfo->dobj.name,
+                                                        tbinfo->dobj.name);
                                exit_nicely(1);
                        }
 
@@ -17219,14 +17350,13 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 
        if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
-                                        tag,
-                                        tbinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tbinfo->rolname, false,
-                                        "TRIGGER", SECTION_POST_DATA,
-                                        query->data, delqry->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "TRIGGER",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = query->data,
+                                                                 .dropStmt = delqry->data));
 
        if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
                dumpComment(fout, trigprefix->data, qtabname,
@@ -17273,7 +17403,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
                appendPQExpBufferChar(query, ')');
        }
 
-       appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
+       appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
        appendPQExpBufferStr(query, evtinfo->evtfname);
        appendPQExpBufferStr(query, "();\n");
 
@@ -17302,14 +17432,18 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
        appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
                                          qevtname);
 
+       if (dopt->binary_upgrade)
+               binary_upgrade_extension_member(query, &evtinfo->dobj,
+                                                                               "EVENT TRIGGER", qevtname, NULL);
+
        if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
-                                        evtinfo->dobj.name, NULL, NULL,
-                                        evtinfo->evtowner, false,
-                                        "EVENT TRIGGER", SECTION_POST_DATA,
-                                        query->data, delqry->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
+                                                                 .owner = evtinfo->evtowner,
+                                                                 .description = "EVENT TRIGGER",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = query->data,
+                                                                 .dropStmt = delqry->data));
 
        if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
                dumpComment(fout, "EVENT TRIGGER", qevtname,
@@ -17398,8 +17532,8 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 
                if (PQntuples(res) != 1)
                {
-                       write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
-                                         rinfo->dobj.name, tbinfo->dobj.name);
+                       pg_log_error("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
+                                                rinfo->dobj.name, tbinfo->dobj.name);
                        exit_nicely(1);
                }
 
@@ -17462,14 +17596,13 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 
        if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
-                                        tag,
-                                        tbinfo->dobj.namespace->dobj.name,
-                                        NULL,
-                                        tbinfo->rolname, false,
-                                        "RULE", SECTION_POST_DATA,
-                                        cmd->data, delcmd->data, NULL,
-                                        NULL, 0,
-                                        NULL, NULL);
+                                        ARCHIVE_OPTS(.tag = tag,
+                                                                 .namespace = tbinfo->dobj.namespace->dobj.name,
+                                                                 .owner = tbinfo->rolname,
+                                                                 .description = "RULE",
+                                                                 .section = SECTION_POST_DATA,
+                                                                 .createStmt = cmd->data,
+                                                                 .dropStmt = delcmd->data));
 
        /* Dump rule comments */
        if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
@@ -17561,7 +17694,7 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
                if (ext == NULL)
                {
                        /* shouldn't happen */
-                       fprintf(stderr, "could not find referenced extension %u\n", extId);
+                       pg_log_warning("could not find referenced extension %u", extId);
                        continue;
                }
 
@@ -17685,12 +17818,7 @@ processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
 
                                if (dumpobj)
                                {
-                                       /*
-                                        * Note: config tables are dumped without OIDs regardless
-                                        * of the --oids setting.  This is because row filtering
-                                        * conditions aren't compatible with dumping OIDs.
-                                        */
-                                       makeTableDataInfo(dopt, configtbl, false);
+                                       makeTableDataInfo(dopt, configtbl);
                                        if (configtbl->dataObj != NULL)
                                        {
                                                if (strlen(extconditionarray[j]) > 0)
@@ -17778,20 +17906,57 @@ getDependencies(Archive *fout)
        DumpableObject *dobj,
                           *refdobj;
 
-       if (g_verbose)
-               write_msg(NULL, "reading dependency data\n");
+       pg_log_info("reading dependency data");
 
        query = createPQExpBuffer();
 
        /*
+        * Messy query to collect the dependency data we need.  Note that we
+        * ignore the sub-object column, so that dependencies of or on a column
+        * look the same as dependencies of or on a whole table.
+        *
         * PIN dependencies aren't interesting, and EXTENSION dependencies were
         * already processed by getExtensionMembership.
         */
        appendPQExpBufferStr(query, "SELECT "
                                                 "classid, objid, refclassid, refobjid, deptype "
                                                 "FROM pg_depend "
-                                                "WHERE deptype != 'p' AND deptype != 'e' "
-                                                "ORDER BY 1,2");
+                                                "WHERE deptype != 'p' AND deptype != 'e'\n");
+
+       /*
+        * Since we don't treat pg_amop entries as separate DumpableObjects, we
+        * have to translate their dependencies into dependencies of their parent
+        * opfamily.  Ignore internal dependencies though, as those will point to
+        * their parent opclass, which we needn't consider here (and if we did,
+        * it'd just result in circular dependencies).  Also, "loose" opfamily
+        * entries will have dependencies on their parent opfamily, which we
+        * should drop since they'd likewise become useless self-dependencies.
+        * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
+        *
+        * Skip this for pre-8.3 source servers: pg_opfamily doesn't exist there,
+        * and the (known) cases where it would matter to have these dependencies
+        * can't arise anyway.
+        */
+       if (fout->remoteVersion >= 80300)
+       {
+               appendPQExpBufferStr(query, "UNION ALL\n"
+                                                        "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
+                                                        "FROM pg_depend d, pg_amop o "
+                                                        "WHERE deptype NOT IN ('p', 'e', 'i') AND "
+                                                        "classid = 'pg_amop'::regclass AND objid = o.oid "
+                                                        "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
+
+               /* Likewise for pg_amproc entries */
+               appendPQExpBufferStr(query, "UNION ALL\n"
+                                                        "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
+                                                        "FROM pg_depend d, pg_amproc p "
+                                                        "WHERE deptype NOT IN ('p', 'e', 'i') AND "
+                                                        "classid = 'pg_amproc'::regclass AND objid = p.oid "
+                                                        "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
+       }
+
+       /* Sort the output for efficiency below */
+       appendPQExpBufferStr(query, "ORDER BY 1,2");
 
        res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -17834,8 +17999,8 @@ getDependencies(Archive *fout)
                if (dobj == NULL)
                {
 #ifdef NOT_USED
-                       fprintf(stderr, "no referencing object %u %u\n",
-                                       objId.tableoid, objId.oid);
+                       pg_log_warning("no referencing object %u %u",
+                                                  objId.tableoid, objId.oid);
 #endif
                        continue;
                }
@@ -17845,8 +18010,8 @@ getDependencies(Archive *fout)
                if (refdobj == NULL)
                {
 #ifdef NOT_USED
-                       fprintf(stderr, "no referenced object %u %u\n",
-                                       refobjId.tableoid, refobjId.oid);
+                       pg_log_warning("no referenced object %u %u",
+                                                  refobjId.tableoid, refobjId.oid);
 #endif
                        continue;
                }
@@ -18164,6 +18329,7 @@ fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
        int                     numatts = ti->numatts;
        char      **attnames = ti->attnames;
        bool       *attisdropped = ti->attisdropped;
+       char       *attgenerated = ti->attgenerated;
        bool            needComma;
        int                     i;
 
@@ -18173,6 +18339,8 @@ fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
        {
                if (attisdropped[i])
                        continue;
+               if (attgenerated[i])
+                       continue;
                if (needComma)
                        appendPQExpBufferStr(buffer, ", ");
                appendPQExpBufferStr(buffer, fmtId(attnames[i]));
@@ -18210,5 +18378,5 @@ appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
        res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
                                                                fout->std_strings);
        if (!res)
-               write_msg(NULL, "WARNING: could not parse reloptions array\n");
+               pg_log_warning("could not parse reloptions array");
 }