LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 5953 6819 87.3 %
Date: 2019-11-15 23:07:02 Functions: 156 160 97.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_dump.c
       4             :  *    pg_dump is a utility for dumping out a postgres database
       5             :  *    into a script file.
       6             :  *
       7             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  *  pg_dump will read the system catalogs in a database and dump out a
      11             :  *  script that reproduces the schema in terms of SQL that is understood
      12             :  *  by PostgreSQL
      13             :  *
      14             :  *  Note that pg_dump runs in a transaction-snapshot mode transaction,
      15             :  *  so it sees a consistent snapshot of the database including system
      16             :  *  catalogs. However, it relies in part on various specialized backend
      17             :  *  functions like pg_get_indexdef(), and those things tend to look at
      18             :  *  the currently committed state.  So it is possible to get 'cache
      19             :  *  lookup failed' error if someone performs DDL changes while a dump is
      20             :  *  happening. The window for this sort of thing is from the acquisition
      21             :  *  of the transaction snapshot to getSchemaData() (when pg_dump acquires
      22             :  *  AccessShareLock on every table it intends to dump). It isn't very large,
      23             :  *  but it can happen.
      24             :  *
      25             :  *  http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
      26             :  *
      27             :  * IDENTIFICATION
      28             :  *    src/bin/pg_dump/pg_dump.c
      29             :  *
      30             :  *-------------------------------------------------------------------------
      31             :  */
      32             : #include "postgres_fe.h"
      33             : 
      34             : #include <unistd.h>
      35             : #include <ctype.h>
      36             : #include <limits.h>
      37             : #ifdef HAVE_TERMIOS_H
      38             : #include <termios.h>
      39             : #endif
      40             : 
      41             : #include "access/attnum.h"
      42             : #include "access/sysattr.h"
      43             : #include "access/transam.h"
      44             : #include "catalog/pg_aggregate_d.h"
      45             : #include "catalog/pg_am_d.h"
      46             : #include "catalog/pg_attribute_d.h"
      47             : #include "catalog/pg_cast_d.h"
      48             : #include "catalog/pg_class_d.h"
      49             : #include "catalog/pg_default_acl_d.h"
      50             : #include "catalog/pg_largeobject_d.h"
      51             : #include "catalog/pg_largeobject_metadata_d.h"
      52             : #include "catalog/pg_proc_d.h"
      53             : #include "catalog/pg_trigger_d.h"
      54             : #include "catalog/pg_type_d.h"
      55             : #include "dumputils.h"
      56             : #include "fe_utils/connect.h"
      57             : #include "fe_utils/string_utils.h"
      58             : #include "getopt_long.h"
      59             : #include "libpq/libpq-fs.h"
      60             : #include "parallel.h"
      61             : #include "pg_backup_db.h"
      62             : #include "pg_backup_utils.h"
      63             : #include "pg_dump.h"
      64             : #include "storage/block.h"
      65             : 
      66             : typedef struct
      67             : {
      68             :     const char *descr;          /* comment for an object */
      69             :     Oid         classoid;       /* object class (catalog OID) */
      70             :     Oid         objoid;         /* object OID */
      71             :     int         objsubid;       /* subobject (table column #) */
      72             : } CommentItem;
      73             : 
      74             : typedef struct
      75             : {
      76             :     const char *provider;       /* label provider of this security label */
      77             :     const char *label;          /* security label for an object */
      78             :     Oid         classoid;       /* object class (catalog OID) */
      79             :     Oid         objoid;         /* object OID */
      80             :     int         objsubid;       /* subobject (table column #) */
      81             : } SecLabelItem;
      82             : 
      83             : typedef enum OidOptions
      84             : {
      85             :     zeroAsOpaque = 1,
      86             :     zeroAsAny = 2,
      87             :     zeroAsStar = 4,
      88             :     zeroAsNone = 8
      89             : } OidOptions;
      90             : 
      91             : /* global decls */
      92             : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
      93             : 
      94             : /* subquery used to convert user ID (eg, datdba) to user name */
      95             : static const char *username_subquery;
      96             : 
      97             : /*
      98             :  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
      99             :  * FirstNormalObjectId - 1.
     100             :  */
     101             : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     102             : 
     103             : /* The specified names/patterns should to match at least one entity */
     104             : static int  strict_names = 0;
     105             : 
     106             : /*
     107             :  * Object inclusion/exclusion lists
     108             :  *
     109             :  * The string lists record the patterns given by command-line switches,
     110             :  * which we then convert to lists of OIDs of matching objects.
     111             :  */
     112             : static SimpleStringList schema_include_patterns = {NULL, NULL};
     113             : static SimpleOidList schema_include_oids = {NULL, NULL};
     114             : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     115             : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     116             : 
     117             : static SimpleStringList table_include_patterns = {NULL, NULL};
     118             : static SimpleOidList table_include_oids = {NULL, NULL};
     119             : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     120             : static SimpleOidList table_exclude_oids = {NULL, NULL};
     121             : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     122             : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     123             : 
     124             : 
     125             : char        g_opaque_type[10];  /* name for the opaque type */
     126             : 
     127             : /* placeholders for the delimiters for comments */
     128             : char        g_comment_start[10];
     129             : char        g_comment_end[10];
     130             : 
     131             : static const CatalogId nilCatalogId = {0, 0};
     132             : 
     133             : /* override for standard extra_float_digits setting */
     134             : static bool have_extra_float_digits = false;
     135             : static int  extra_float_digits;
     136             : 
     137             : /*
     138             :  * The default number of rows per INSERT when
     139             :  * --inserts is specified without --rows-per-insert
     140             :  */
     141             : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     142             : 
     143             : /*
     144             :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     145             :  */
     146             : #define fmtQualifiedDumpable(obj) \
     147             :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     148             :                    (obj)->dobj.name)
     149             : 
     150             : static void help(const char *progname);
     151             : static void setup_connection(Archive *AH,
     152             :                              const char *dumpencoding, const char *dumpsnapshot,
     153             :                              char *use_role);
     154             : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     155             : static void expand_schema_name_patterns(Archive *fout,
     156             :                                         SimpleStringList *patterns,
     157             :                                         SimpleOidList *oids,
     158             :                                         bool strict_names);
     159             : static void expand_table_name_patterns(Archive *fout,
     160             :                                        SimpleStringList *patterns,
     161             :                                        SimpleOidList *oids,
     162             :                                        bool strict_names);
     163             : static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
     164             : static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
     165             : static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
     166             : static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
     167             : static void dumpComment(Archive *fout, const char *type, const char *name,
     168             :                         const char *namespace, const char *owner,
     169             :                         CatalogId catalogId, int subid, DumpId dumpId);
     170             : static int  findComments(Archive *fout, Oid classoid, Oid objoid,
     171             :                          CommentItem **items);
     172             : static int  collectComments(Archive *fout, CommentItem **items);
     173             : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     174             :                          const char *namespace, const char *owner,
     175             :                          CatalogId catalogId, int subid, DumpId dumpId);
     176             : static int  findSecLabels(Archive *fout, Oid classoid, Oid objoid,
     177             :                           SecLabelItem **items);
     178             : static int  collectSecLabels(Archive *fout, SecLabelItem **items);
     179             : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     180             : static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
     181             : static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
     182             : static void dumpType(Archive *fout, TypeInfo *tyinfo);
     183             : static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
     184             : static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
     185             : static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
     186             : static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
     187             : static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
     188             : static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
     189             : static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
     190             : static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
     191             : static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
     192             : static void dumpFunc(Archive *fout, FuncInfo *finfo);
     193             : static void dumpCast(Archive *fout, CastInfo *cast);
     194             : static void dumpTransform(Archive *fout, TransformInfo *transform);
     195             : static void dumpOpr(Archive *fout, OprInfo *oprinfo);
     196             : static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
     197             : static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
     198             : static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
     199             : static void dumpCollation(Archive *fout, CollInfo *collinfo);
     200             : static void dumpConversion(Archive *fout, ConvInfo *convinfo);
     201             : static void dumpRule(Archive *fout, RuleInfo *rinfo);
     202             : static void dumpAgg(Archive *fout, AggInfo *agginfo);
     203             : static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
     204             : static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
     205             : static void dumpTable(Archive *fout, TableInfo *tbinfo);
     206             : static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
     207             : static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
     208             : static void dumpSequence(Archive *fout, TableInfo *tbinfo);
     209             : static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
     210             : static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
     211             : static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
     212             : static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
     213             : static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
     214             : static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
     215             : static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
     216             : static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
     217             : static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
     218             : static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
     219             : static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
     220             : static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
     221             : static void dumpUserMappings(Archive *fout,
     222             :                              const char *servername, const char *namespace,
     223             :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     224             : static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
     225             : 
     226             : static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
     227             :                     const char *type, const char *name, const char *subname,
     228             :                     const char *nspname, const char *owner,
     229             :                     const char *acls, const char *racls,
     230             :                     const char *initacls, const char *initracls);
     231             : 
     232             : static void getDependencies(Archive *fout);
     233             : static void BuildArchiveDependencies(Archive *fout);
     234             : static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
     235             :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     236             : 
     237             : static DumpableObject *createBoundaryObjects(void);
     238             : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     239             :                                     DumpableObject *boundaryObjs);
     240             : 
     241             : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     242             : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     243             : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     244             : static void buildMatViewRefreshDependencies(Archive *fout);
     245             : static void getTableDataFKConstraints(void);
     246             : static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
     247             :                                        bool is_agg);
     248             : static char *format_function_arguments_old(Archive *fout,
     249             :                                            FuncInfo *finfo, int nallargs,
     250             :                                            char **allargtypes,
     251             :                                            char **argmodes,
     252             :                                            char **argnames);
     253             : static char *format_function_signature(Archive *fout,
     254             :                                        FuncInfo *finfo, bool honor_quotes);
     255             : static char *convertRegProcReference(Archive *fout,
     256             :                                      const char *proc);
     257             : static char *getFormattedOperatorName(Archive *fout, const char *oproid);
     258             : static char *convertTSFunction(Archive *fout, Oid funcOid);
     259             : static Oid  findLastBuiltinOid_V71(Archive *fout);
     260             : static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     261             : static void getBlobs(Archive *fout);
     262             : static void dumpBlob(Archive *fout, BlobInfo *binfo);
     263             : static int  dumpBlobs(Archive *fout, void *arg);
     264             : static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
     265             : static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
     266             : static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
     267             : static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
     268             : static void dumpDatabase(Archive *AH);
     269             : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     270             :                                const char *dbname, Oid dboid);
     271             : static void dumpEncoding(Archive *AH);
     272             : static void dumpStdStrings(Archive *AH);
     273             : static void dumpSearchPath(Archive *AH);
     274             : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     275             :                                                      PQExpBuffer upgrade_buffer,
     276             :                                                      Oid pg_type_oid,
     277             :                                                      bool force_array_type);
     278             : static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
     279             :                                                     PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
     280             : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     281             :                                              PQExpBuffer upgrade_buffer,
     282             :                                              Oid pg_class_oid, bool is_index);
     283             : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     284             :                                             DumpableObject *dobj,
     285             :                                             const char *objtype,
     286             :                                             const char *objname,
     287             :                                             const char *objnamespace);
     288             : static const char *getAttrName(int attrnum, TableInfo *tblInfo);
     289             : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     290             : static bool nonemptyReloptions(const char *reloptions);
     291             : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     292             :                                     const char *prefix, Archive *fout);
     293             : static char *get_synchronized_snapshot(Archive *fout);
     294             : static void setupDumpWorker(Archive *AHX);
     295             : static TableInfo *getRootTableInfo(TableInfo *tbinfo);
     296             : 
     297             : 
     298             : int
     299         236 : main(int argc, char **argv)
     300             : {
     301             :     int         c;
     302         236 :     const char *filename = NULL;
     303         236 :     const char *format = "p";
     304             :     TableInfo  *tblinfo;
     305             :     int         numTables;
     306             :     DumpableObject **dobjs;
     307             :     int         numObjs;
     308             :     DumpableObject *boundaryObjs;
     309             :     int         i;
     310             :     int         optindex;
     311             :     char       *endptr;
     312             :     RestoreOptions *ropt;
     313             :     Archive    *fout;           /* the script file */
     314         236 :     bool        g_verbose = false;
     315         236 :     const char *dumpencoding = NULL;
     316         236 :     const char *dumpsnapshot = NULL;
     317         236 :     char       *use_role = NULL;
     318             :     long        rowsPerInsert;
     319         236 :     int         numWorkers = 1;
     320         236 :     trivalue    prompt_password = TRI_DEFAULT;
     321         236 :     int         compressLevel = -1;
     322         236 :     int         plainText = 0;
     323         236 :     ArchiveFormat archiveFormat = archUnknown;
     324             :     ArchiveMode archiveMode;
     325             : 
     326             :     static DumpOptions dopt;
     327             : 
     328             :     static struct option long_options[] = {
     329             :         {"data-only", no_argument, NULL, 'a'},
     330             :         {"blobs", no_argument, NULL, 'b'},
     331             :         {"no-blobs", no_argument, NULL, 'B'},
     332             :         {"clean", no_argument, NULL, 'c'},
     333             :         {"create", no_argument, NULL, 'C'},
     334             :         {"dbname", required_argument, NULL, 'd'},
     335             :         {"file", required_argument, NULL, 'f'},
     336             :         {"format", required_argument, NULL, 'F'},
     337             :         {"host", required_argument, NULL, 'h'},
     338             :         {"jobs", 1, NULL, 'j'},
     339             :         {"no-reconnect", no_argument, NULL, 'R'},
     340             :         {"no-owner", no_argument, NULL, 'O'},
     341             :         {"port", required_argument, NULL, 'p'},
     342             :         {"schema", required_argument, NULL, 'n'},
     343             :         {"exclude-schema", required_argument, NULL, 'N'},
     344             :         {"schema-only", no_argument, NULL, 's'},
     345             :         {"superuser", required_argument, NULL, 'S'},
     346             :         {"table", required_argument, NULL, 't'},
     347             :         {"exclude-table", required_argument, NULL, 'T'},
     348             :         {"no-password", no_argument, NULL, 'w'},
     349             :         {"password", no_argument, NULL, 'W'},
     350             :         {"username", required_argument, NULL, 'U'},
     351             :         {"verbose", no_argument, NULL, 'v'},
     352             :         {"no-privileges", no_argument, NULL, 'x'},
     353             :         {"no-acl", no_argument, NULL, 'x'},
     354             :         {"compress", required_argument, NULL, 'Z'},
     355             :         {"encoding", required_argument, NULL, 'E'},
     356             :         {"help", no_argument, NULL, '?'},
     357             :         {"version", no_argument, NULL, 'V'},
     358             : 
     359             :         /*
     360             :          * the following options don't have an equivalent short option letter
     361             :          */
     362             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     363             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     364             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     365             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     366             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     367             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     368             :         {"exclude-table-data", required_argument, NULL, 4},
     369             :         {"extra-float-digits", required_argument, NULL, 8},
     370             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     371             :         {"inserts", no_argument, NULL, 9},
     372             :         {"lock-wait-timeout", required_argument, NULL, 2},
     373             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     374             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     375             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     376             :         {"role", required_argument, NULL, 3},
     377             :         {"section", required_argument, NULL, 5},
     378             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     379             :         {"snapshot", required_argument, NULL, 6},
     380             :         {"strict-names", no_argument, &strict_names, 1},
     381             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     382             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     383             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     384             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     385             :         {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
     386             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     387             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     388             :         {"no-sync", no_argument, NULL, 7},
     389             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     390             :         {"rows-per-insert", required_argument, NULL, 10},
     391             : 
     392             :         {NULL, 0, NULL, 0}
     393             :     };
     394             : 
     395         236 :     pg_logging_init(argv[0]);
     396         236 :     pg_logging_set_level(PG_LOG_WARNING);
     397         236 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     398             : 
     399             :     /*
     400             :      * Initialize what we need for parallel execution, especially for thread
     401             :      * support on Windows.
     402             :      */
     403         236 :     init_parallel_dump_utils();
     404             : 
     405         236 :     strcpy(g_comment_start, "-- ");
     406         236 :     g_comment_end[0] = '\0';
     407         236 :     strcpy(g_opaque_type, "opaque");
     408             : 
     409         236 :     progname = get_progname(argv[0]);
     410             : 
     411         236 :     if (argc > 1)
     412             :     {
     413         236 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     414             :         {
     415           2 :             help(progname);
     416           2 :             exit_nicely(0);
     417             :         }
     418         234 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     419             :         {
     420          46 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     421          46 :             exit_nicely(0);
     422             :         }
     423             :     }
     424             : 
     425         188 :     InitDumpOptions(&dopt);
     426             : 
     427         188 :     while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
     428             :                             long_options, &optindex)) != -1)
     429             :     {
     430         670 :         switch (c)
     431             :         {
     432             :             case 'a':           /* Dump data only */
     433          12 :                 dopt.dataOnly = true;
     434          12 :                 break;
     435             : 
     436             :             case 'b':           /* Dump blobs */
     437           2 :                 dopt.outputBlobs = true;
     438           2 :                 break;
     439             : 
     440             :             case 'B':           /* Don't dump blobs */
     441           4 :                 dopt.dontOutputBlobs = true;
     442           4 :                 break;
     443             : 
     444             :             case 'c':           /* clean (i.e., drop) schema prior to create */
     445          12 :                 dopt.outputClean = 1;
     446          12 :                 break;
     447             : 
     448             :             case 'C':           /* Create DB */
     449          34 :                 dopt.outputCreateDB = 1;
     450          34 :                 break;
     451             : 
     452             :             case 'd':           /* database name */
     453           8 :                 dopt.dbname = pg_strdup(optarg);
     454           8 :                 break;
     455             : 
     456             :             case 'E':           /* Dump encoding */
     457           4 :                 dumpencoding = pg_strdup(optarg);
     458           4 :                 break;
     459             : 
     460             :             case 'f':
     461         156 :                 filename = pg_strdup(optarg);
     462         156 :                 break;
     463             : 
     464             :             case 'F':
     465          90 :                 format = pg_strdup(optarg);
     466          90 :                 break;
     467             : 
     468             :             case 'h':           /* server host */
     469          12 :                 dopt.pghost = pg_strdup(optarg);
     470          12 :                 break;
     471             : 
     472             :             case 'j':           /* number of dump jobs */
     473          12 :                 numWorkers = atoi(optarg);
     474          12 :                 break;
     475             : 
     476             :             case 'n':           /* include schema(s) */
     477          12 :                 simple_string_list_append(&schema_include_patterns, optarg);
     478          12 :                 dopt.include_everything = false;
     479          12 :                 break;
     480             : 
     481             :             case 'N':           /* exclude schema(s) */
     482           2 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     483           2 :                 break;
     484             : 
     485             :             case 'O':           /* Don't reconnect to match owner */
     486           4 :                 dopt.outputNoOwner = 1;
     487           4 :                 break;
     488             : 
     489             :             case 'p':           /* server port */
     490          24 :                 dopt.pgport = pg_strdup(optarg);
     491          24 :                 break;
     492             : 
     493             :             case 'R':
     494             :                 /* no-op, still accepted for backwards compatibility */
     495           4 :                 break;
     496             : 
     497             :             case 's':           /* dump schema only */
     498          22 :                 dopt.schemaOnly = true;
     499          22 :                 break;
     500             : 
     501             :             case 'S':           /* Username for superuser in plain text output */
     502           2 :                 dopt.outputSuperuser = pg_strdup(optarg);
     503           2 :                 break;
     504             : 
     505             :             case 't':           /* include table(s) */
     506          10 :                 simple_string_list_append(&table_include_patterns, optarg);
     507          10 :                 dopt.include_everything = false;
     508          10 :                 break;
     509             : 
     510             :             case 'T':           /* exclude table(s) */
     511           2 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     512           2 :                 break;
     513             : 
     514             :             case 'U':
     515          14 :                 dopt.username = pg_strdup(optarg);
     516          14 :                 break;
     517             : 
     518             :             case 'v':           /* verbose */
     519          10 :                 g_verbose = true;
     520          10 :                 pg_logging_set_level(PG_LOG_INFO);
     521          10 :                 break;
     522             : 
     523             :             case 'w':
     524           2 :                 prompt_password = TRI_NO;
     525           2 :                 break;
     526             : 
     527             :             case 'W':
     528           0 :                 prompt_password = TRI_YES;
     529           0 :                 break;
     530             : 
     531             :             case 'x':           /* skip ACL dump */
     532           4 :                 dopt.aclsSkip = true;
     533           4 :                 break;
     534             : 
     535             :             case 'Z':           /* Compression Level */
     536           6 :                 compressLevel = atoi(optarg);
     537           6 :                 if (compressLevel < 0 || compressLevel > 9)
     538             :                 {
     539           2 :                     pg_log_error("compression level must be in range 0..9");
     540           2 :                     exit_nicely(1);
     541             :                 }
     542           4 :                 break;
     543             : 
     544             :             case 0:
     545             :                 /* This covers the long options. */
     546          46 :                 break;
     547             : 
     548             :             case 2:             /* lock-wait-timeout */
     549           2 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     550           2 :                 break;
     551             : 
     552             :             case 3:             /* SET ROLE */
     553           6 :                 use_role = pg_strdup(optarg);
     554           6 :                 break;
     555             : 
     556             :             case 4:             /* exclude table(s) data */
     557           2 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     558           2 :                 break;
     559             : 
     560             :             case 5:             /* section */
     561          12 :                 set_dump_section(optarg, &dopt.dumpSections);
     562          12 :                 break;
     563             : 
     564             :             case 6:             /* snapshot */
     565           0 :                 dumpsnapshot = pg_strdup(optarg);
     566           0 :                 break;
     567             : 
     568             :             case 7:             /* no-sync */
     569         134 :                 dosync = false;
     570         134 :                 break;
     571             : 
     572             :             case 8:
     573           0 :                 have_extra_float_digits = true;
     574           0 :                 extra_float_digits = atoi(optarg);
     575           0 :                 if (extra_float_digits < -15 || extra_float_digits > 3)
     576             :                 {
     577           0 :                     pg_log_error("extra_float_digits must be in range -15..3");
     578           0 :                     exit_nicely(1);
     579             :                 }
     580           0 :                 break;
     581             : 
     582             :             case 9:             /* inserts */
     583             : 
     584             :                 /*
     585             :                  * dump_inserts also stores --rows-per-insert, careful not to
     586             :                  * overwrite that.
     587             :                  */
     588           0 :                 if (dopt.dump_inserts == 0)
     589           0 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     590           0 :                 break;
     591             : 
     592             :             case 10:            /* rows per insert */
     593           2 :                 errno = 0;
     594           2 :                 rowsPerInsert = strtol(optarg, &endptr, 10);
     595             : 
     596           2 :                 if (endptr == optarg || *endptr != '\0' ||
     597           4 :                     rowsPerInsert <= 0 || rowsPerInsert > INT_MAX ||
     598           2 :                     errno == ERANGE)
     599             :                 {
     600           0 :                     pg_log_error("rows-per-insert must be in range %d..%d",
     601             :                                  1, INT_MAX);
     602           0 :                     exit_nicely(1);
     603             :                 }
     604           2 :                 dopt.dump_inserts = (int) rowsPerInsert;
     605           2 :                 break;
     606             : 
     607             :             default:
     608           2 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     609           2 :                 exit_nicely(1);
     610             :         }
     611             :     }
     612             : 
     613             :     /*
     614             :      * Non-option argument specifies database name as long as it wasn't
     615             :      * already specified with -d / --dbname
     616             :      */
     617         184 :     if (optind < argc && dopt.dbname == NULL)
     618         152 :         dopt.dbname = argv[optind++];
     619             : 
     620             :     /* Complain if any arguments remain */
     621         184 :     if (optind < argc)
     622             :     {
     623           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     624             :                      argv[optind]);
     625           2 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
     626             :                 progname);
     627           2 :         exit_nicely(1);
     628             :     }
     629             : 
     630             :     /* --column-inserts implies --inserts */
     631         182 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     632           2 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     633             : 
     634             :     /*
     635             :      * Binary upgrade mode implies dumping sequence data even in schema-only
     636             :      * mode.  This is not exposed as a separate option, but kept separate
     637             :      * internally for clarity.
     638             :      */
     639         182 :     if (dopt.binary_upgrade)
     640          16 :         dopt.sequence_data = 1;
     641             : 
     642         182 :     if (dopt.dataOnly && dopt.schemaOnly)
     643             :     {
     644           2 :         pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together");
     645           2 :         exit_nicely(1);
     646             :     }
     647             : 
     648         180 :     if (dopt.dataOnly && dopt.outputClean)
     649             :     {
     650           2 :         pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
     651           2 :         exit_nicely(1);
     652             :     }
     653             : 
     654         178 :     if (dopt.if_exists && !dopt.outputClean)
     655           2 :         fatal("option --if-exists requires option -c/--clean");
     656             : 
     657             :     /*
     658             :      * --inserts are already implied above if --column-inserts or
     659             :      * --rows-per-insert were specified.
     660             :      */
     661         176 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     662           2 :         fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
     663             : 
     664             :     /* Identify archive format to emit */
     665         174 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     666             : 
     667             :     /* archiveFormat specific setup */
     668         172 :     if (archiveFormat == archNull)
     669         138 :         plainText = 1;
     670             : 
     671             :     /* Custom and directory formats are compressed by default, others not */
     672         172 :     if (compressLevel == -1)
     673             :     {
     674             : #ifdef HAVE_LIBZ
     675         168 :         if (archiveFormat == archCustom || archiveFormat == archDirectory)
     676          26 :             compressLevel = Z_DEFAULT_COMPRESSION;
     677             :         else
     678             : #endif
     679         142 :             compressLevel = 0;
     680             :     }
     681             : 
     682             : #ifndef HAVE_LIBZ
     683             :     if (compressLevel != 0)
     684             :         pg_log_warning("requested compression not available in this installation -- archive will be uncompressed");
     685             :     compressLevel = 0;
     686             : #endif
     687             : 
     688             :     /*
     689             :      * If emitting an archive format, we always want to emit a DATABASE item,
     690             :      * in case --create is specified at pg_restore time.
     691             :      */
     692         172 :     if (!plainText)
     693          34 :         dopt.outputCreateDB = 1;
     694             : 
     695             :     /*
     696             :      * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
     697             :      * parallel jobs because that's the maximum limit for the
     698             :      * WaitForMultipleObjects() call.
     699             :      */
     700         172 :     if (numWorkers <= 0
     701             : #ifdef WIN32
     702             :         || numWorkers > MAXIMUM_WAIT_OBJECTS
     703             : #endif
     704             :         )
     705           2 :         fatal("invalid number of parallel jobs");
     706             : 
     707             :     /* Parallel backup only in the directory archive format so far */
     708         170 :     if (archiveFormat != archDirectory && numWorkers > 1)
     709           2 :         fatal("parallel backup only supported by the directory format");
     710             : 
     711             :     /* Open the output file */
     712         168 :     fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
     713             :                          archiveMode, setupDumpWorker);
     714             : 
     715             :     /* Make dump options accessible right away */
     716         168 :     SetArchiveOptions(fout, &dopt, NULL);
     717             : 
     718             :     /* Register the cleanup hook */
     719         168 :     on_exit_close_archive(fout);
     720             : 
     721             :     /* Let the archiver know how noisy to be */
     722         168 :     fout->verbose = g_verbose;
     723             : 
     724             : 
     725             :     /*
     726             :      * We allow the server to be back to 8.0, and up to any minor release of
     727             :      * our own major version.  (See also version check in pg_dumpall.c.)
     728             :      */
     729         168 :     fout->minRemoteVersion = 80000;
     730         168 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     731             : 
     732         168 :     fout->numWorkers = numWorkers;
     733             : 
     734             :     /*
     735             :      * Open the database using the Archiver, so it knows about it. Errors mean
     736             :      * death.
     737             :      */
     738         168 :     ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
     739         166 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     740             : 
     741             :     /*
     742             :      * Disable security label support if server version < v9.1.x (prevents
     743             :      * access to nonexistent pg_seclabel catalog)
     744             :      */
     745         166 :     if (fout->remoteVersion < 90100)
     746           0 :         dopt.no_security_labels = 1;
     747             : 
     748             :     /*
     749             :      * On hot standbys, never try to dump unlogged table data, since it will
     750             :      * just throw an error.
     751             :      */
     752         166 :     if (fout->isStandby)
     753           0 :         dopt.no_unlogged_table_data = true;
     754             : 
     755             :     /* Select the appropriate subquery to convert user IDs to names */
     756         166 :     if (fout->remoteVersion >= 80100)
     757         166 :         username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
     758             :     else
     759           0 :         username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
     760             : 
     761             :     /* check the version for the synchronized snapshots feature */
     762         166 :     if (numWorkers > 1 && fout->remoteVersion < 90200
     763           0 :         && !dopt.no_synchronized_snapshots)
     764           0 :         fatal("Synchronized snapshots are not supported by this server version.\n"
     765             :               "Run with --no-synchronized-snapshots instead if you do not need\n"
     766             :               "synchronized snapshots.");
     767             : 
     768             :     /* check the version when a snapshot is explicitly specified by user */
     769         166 :     if (dumpsnapshot && fout->remoteVersion < 90200)
     770           0 :         fatal("Exported snapshots are not supported by this server version.");
     771             : 
     772             :     /*
     773             :      * Find the last built-in OID, if needed (prior to 8.1)
     774             :      *
     775             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
     776             :      */
     777         166 :     if (fout->remoteVersion < 80100)
     778           0 :         g_last_builtin_oid = findLastBuiltinOid_V71(fout);
     779             :     else
     780         166 :         g_last_builtin_oid = FirstNormalObjectId - 1;
     781             : 
     782         166 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
     783             : 
     784             :     /* Expand schema selection patterns into OID lists */
     785         166 :     if (schema_include_patterns.head != NULL)
     786             :     {
     787          12 :         expand_schema_name_patterns(fout, &schema_include_patterns,
     788             :                                     &schema_include_oids,
     789             :                                     strict_names);
     790          10 :         if (schema_include_oids.head == NULL)
     791           2 :             fatal("no matching schemas were found");
     792             :     }
     793         162 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
     794             :                                 &schema_exclude_oids,
     795             :                                 false);
     796             :     /* non-matching exclusion patterns aren't an error */
     797             : 
     798             :     /* Expand table selection patterns into OID lists */
     799         162 :     if (table_include_patterns.head != NULL)
     800             :     {
     801           8 :         expand_table_name_patterns(fout, &table_include_patterns,
     802             :                                    &table_include_oids,
     803             :                                    strict_names);
     804           6 :         if (table_include_oids.head == NULL)
     805           2 :             fatal("no matching tables were found");
     806             :     }
     807         158 :     expand_table_name_patterns(fout, &table_exclude_patterns,
     808             :                                &table_exclude_oids,
     809             :                                false);
     810             : 
     811         158 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
     812             :                                &tabledata_exclude_oids,
     813             :                                false);
     814             : 
     815             :     /* non-matching exclusion patterns aren't an error */
     816             : 
     817             :     /*
     818             :      * Dumping blobs is the default for dumps where an inclusion switch is not
     819             :      * used (an "include everything" dump).  -B can be used to exclude blobs
     820             :      * from those dumps.  -b can be used to include blobs even when an
     821             :      * inclusion switch is used.
     822             :      *
     823             :      * -s means "schema only" and blobs are data, not schema, so we never
     824             :      * include blobs when -s is used.
     825             :      */
     826         158 :     if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
     827         124 :         dopt.outputBlobs = true;
     828             : 
     829             :     /*
     830             :      * Now scan the database and create DumpableObject structs for all the
     831             :      * objects we intend to dump.
     832             :      */
     833         158 :     tblinfo = getSchemaData(fout, &numTables);
     834             : 
     835         156 :     if (fout->remoteVersion < 80400)
     836           0 :         guessConstraintInheritance(tblinfo, numTables);
     837             : 
     838         156 :     if (!dopt.schemaOnly)
     839             :     {
     840         136 :         getTableData(&dopt, tblinfo, numTables, 0);
     841         136 :         buildMatViewRefreshDependencies(fout);
     842         136 :         if (dopt.dataOnly)
     843           8 :             getTableDataFKConstraints();
     844             :     }
     845             : 
     846         156 :     if (dopt.schemaOnly && dopt.sequence_data)
     847          16 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
     848             : 
     849             :     /*
     850             :      * In binary-upgrade mode, we do not have to worry about the actual blob
     851             :      * data or the associated metadata that resides in the pg_largeobject and
     852             :      * pg_largeobject_metadata tables, respectively.
     853             :      *
     854             :      * However, we do need to collect blob information as there may be
     855             :      * comments or other information on blobs that we do need to dump out.
     856             :      */
     857         156 :     if (dopt.outputBlobs || dopt.binary_upgrade)
     858         140 :         getBlobs(fout);
     859             : 
     860             :     /*
     861             :      * Collect dependency data to assist in ordering the objects.
     862             :      */
     863         156 :     getDependencies(fout);
     864             : 
     865             :     /* Lastly, create dummy objects to represent the section boundaries */
     866         156 :     boundaryObjs = createBoundaryObjects();
     867             : 
     868             :     /* Get pointers to all the known DumpableObjects */
     869         156 :     getDumpableObjects(&dobjs, &numObjs);
     870             : 
     871             :     /*
     872             :      * Add dummy dependencies to enforce the dump section ordering.
     873             :      */
     874         156 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
     875             : 
     876             :     /*
     877             :      * Sort the objects into a safe dump order (no forward references).
     878             :      *
     879             :      * We rely on dependency information to help us determine a safe order, so
     880             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
     881             :      * ensure that logically identical schemas will dump identically.
     882             :      */
     883         156 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
     884             : 
     885         156 :     sortDumpableObjects(dobjs, numObjs,
     886         156 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
     887             : 
     888             :     /*
     889             :      * Create archive TOC entries for all the objects to be dumped, in a safe
     890             :      * order.
     891             :      */
     892             : 
     893             :     /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
     894         156 :     dumpEncoding(fout);
     895         156 :     dumpStdStrings(fout);
     896         156 :     dumpSearchPath(fout);
     897             : 
     898             :     /* The database items are always next, unless we don't want them at all */
     899         156 :     if (dopt.outputCreateDB)
     900          68 :         dumpDatabase(fout);
     901             : 
     902             :     /* Now the rearrangeable objects. */
     903      376586 :     for (i = 0; i < numObjs; i++)
     904      376430 :         dumpDumpableObject(fout, dobjs[i]);
     905             : 
     906             :     /*
     907             :      * Set up options info to ensure we dump what we want.
     908             :      */
     909         156 :     ropt = NewRestoreOptions();
     910         156 :     ropt->filename = filename;
     911             : 
     912             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
     913         156 :     ropt->dropSchema = dopt.outputClean;
     914         156 :     ropt->dataOnly = dopt.dataOnly;
     915         156 :     ropt->schemaOnly = dopt.schemaOnly;
     916         156 :     ropt->if_exists = dopt.if_exists;
     917         156 :     ropt->column_inserts = dopt.column_inserts;
     918         156 :     ropt->dumpSections = dopt.dumpSections;
     919         156 :     ropt->aclsSkip = dopt.aclsSkip;
     920         156 :     ropt->superuser = dopt.outputSuperuser;
     921         156 :     ropt->createDB = dopt.outputCreateDB;
     922         156 :     ropt->noOwner = dopt.outputNoOwner;
     923         156 :     ropt->noTablespace = dopt.outputNoTablespaces;
     924         156 :     ropt->disable_triggers = dopt.disable_triggers;
     925         156 :     ropt->use_setsessauth = dopt.use_setsessauth;
     926         156 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
     927         156 :     ropt->dump_inserts = dopt.dump_inserts;
     928         156 :     ropt->no_comments = dopt.no_comments;
     929         156 :     ropt->no_publications = dopt.no_publications;
     930         156 :     ropt->no_security_labels = dopt.no_security_labels;
     931         156 :     ropt->no_subscriptions = dopt.no_subscriptions;
     932         156 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
     933         156 :     ropt->include_everything = dopt.include_everything;
     934         156 :     ropt->enable_row_security = dopt.enable_row_security;
     935         156 :     ropt->sequence_data = dopt.sequence_data;
     936         156 :     ropt->binary_upgrade = dopt.binary_upgrade;
     937             : 
     938         156 :     if (compressLevel == -1)
     939          26 :         ropt->compression = 0;
     940             :     else
     941         130 :         ropt->compression = compressLevel;
     942             : 
     943         156 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
     944             : 
     945         156 :     SetArchiveOptions(fout, &dopt, ropt);
     946             : 
     947             :     /* Mark which entries should be output */
     948         156 :     ProcessArchiveRestoreOptions(fout);
     949             : 
     950             :     /*
     951             :      * The archive's TOC entries are now marked as to which ones will actually
     952             :      * be output, so we can set up their dependency lists properly. This isn't
     953             :      * necessary for plain-text output, though.
     954             :      */
     955         156 :     if (!plainText)
     956          34 :         BuildArchiveDependencies(fout);
     957             : 
     958             :     /*
     959             :      * And finally we can do the actual output.
     960             :      *
     961             :      * Note: for non-plain-text output formats, the output file is written
     962             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
     963             :      * right now.
     964             :      */
     965         156 :     if (plainText)
     966         122 :         RestoreArchive(fout);
     967             : 
     968         156 :     CloseArchive(fout);
     969             : 
     970         156 :     exit_nicely(0);
     971             : }
     972             : 
     973             : 
     974             : static void
     975           2 : help(const char *progname)
     976             : {
     977           2 :     printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
     978           2 :     printf(_("Usage:\n"));
     979           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
     980             : 
     981           2 :     printf(_("\nGeneral options:\n"));
     982           2 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
     983           2 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
     984             :              "                               plain text (default))\n"));
     985           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
     986           2 :     printf(_("  -v, --verbose                verbose mode\n"));
     987           2 :     printf(_("  -V, --version                output version information, then exit\n"));
     988           2 :     printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
     989           2 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
     990           2 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
     991           2 :     printf(_("  -?, --help                   show this help, then exit\n"));
     992             : 
     993           2 :     printf(_("\nOptions controlling the output content:\n"));
     994           2 :     printf(_("  -a, --data-only              dump only the data, not the schema\n"));
     995           2 :     printf(_("  -b, --blobs                  include large objects in dump\n"));
     996           2 :     printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
     997           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
     998           2 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
     999           2 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1000           2 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1001           2 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1002           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1003             :              "                               plain-text format\n"));
    1004           2 :     printf(_("  -s, --schema-only            dump only the schema, no data\n"));
    1005           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1006           2 :     printf(_("  -t, --table=PATTERN          dump the specified table(s) only\n"));
    1007           2 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1008           2 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1009           2 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1010           2 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1011           2 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1012           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1013           2 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1014             :              "                               access to)\n"));
    1015           2 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1016           2 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1017           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1018           2 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1019           2 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1020           2 :     printf(_("  --no-comments                do not dump comments\n"));
    1021           2 :     printf(_("  --no-publications            do not dump publications\n"));
    1022           2 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1023           2 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1024           2 :     printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
    1025           2 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1026           2 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1027           2 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1028           2 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1029           2 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1030           2 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1031           2 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1032           2 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1033           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1034             :              "                               match at least one entity each\n"));
    1035           2 :     printf(_("  --use-set-session-authorization\n"
    1036             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1037             :              "                               ALTER OWNER commands to set ownership\n"));
    1038             : 
    1039           2 :     printf(_("\nConnection options:\n"));
    1040           2 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1041           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1042           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1043           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1044           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1045           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1046           2 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1047             : 
    1048           2 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1049             :              "variable value is used.\n\n"));
    1050           2 :     printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
    1051           2 : }
    1052             : 
    1053             : static void
    1054         182 : setup_connection(Archive *AH, const char *dumpencoding,
    1055             :                  const char *dumpsnapshot, char *use_role)
    1056             : {
    1057         182 :     DumpOptions *dopt = AH->dopt;
    1058         182 :     PGconn     *conn = GetConnection(AH);
    1059             :     const char *std_strings;
    1060             : 
    1061         182 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1062             : 
    1063             :     /*
    1064             :      * Set the client encoding if requested.
    1065             :      */
    1066         182 :     if (dumpencoding)
    1067             :     {
    1068          20 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1069           0 :             fatal("invalid client encoding \"%s\" specified",
    1070             :                   dumpencoding);
    1071             :     }
    1072             : 
    1073             :     /*
    1074             :      * Get the active encoding and the standard_conforming_strings setting, so
    1075             :      * we know how to escape strings.
    1076             :      */
    1077         182 :     AH->encoding = PQclientEncoding(conn);
    1078             : 
    1079         182 :     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
    1080         182 :     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
    1081             : 
    1082             :     /*
    1083             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1084             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1085             :      * originally) and we should use that.
    1086             :      */
    1087         182 :     if (!use_role && AH->use_role)
    1088           4 :         use_role = AH->use_role;
    1089             : 
    1090             :     /* Set the role if requested */
    1091         182 :     if (use_role && AH->remoteVersion >= 80100)
    1092             :     {
    1093          10 :         PQExpBuffer query = createPQExpBuffer();
    1094             : 
    1095          10 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1096          10 :         ExecuteSqlStatement(AH, query->data);
    1097          10 :         destroyPQExpBuffer(query);
    1098             : 
    1099             :         /* save it for possible later use by parallel workers */
    1100          10 :         if (!AH->use_role)
    1101           6 :             AH->use_role = pg_strdup(use_role);
    1102             :     }
    1103             : 
    1104             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1105         182 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1106             : 
    1107             :     /* Likewise, avoid using sql_standard intervalstyle */
    1108         182 :     if (AH->remoteVersion >= 80400)
    1109         182 :         ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1110             : 
    1111             :     /*
    1112             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1113             :      * Otherwise, set extra_float_digits so that we can dump float data
    1114             :      * exactly (given correctly implemented float I/O code, anyway).
    1115             :      */
    1116         182 :     if (have_extra_float_digits)
    1117             :     {
    1118           0 :         PQExpBuffer q = createPQExpBuffer();
    1119             : 
    1120           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1121             :                           extra_float_digits);
    1122           0 :         ExecuteSqlStatement(AH, q->data);
    1123           0 :         destroyPQExpBuffer(q);
    1124             :     }
    1125         182 :     else if (AH->remoteVersion >= 90000)
    1126         182 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1127             :     else
    1128           0 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
    1129             : 
    1130             :     /*
    1131             :      * If synchronized scanning is supported, disable it, to prevent
    1132             :      * unpredictable changes in row ordering across a dump and reload.
    1133             :      */
    1134         182 :     if (AH->remoteVersion >= 80300)
    1135         182 :         ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1136             : 
    1137             :     /*
    1138             :      * Disable timeouts if supported.
    1139             :      */
    1140         182 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1141         182 :     if (AH->remoteVersion >= 90300)
    1142         182 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1143         182 :     if (AH->remoteVersion >= 90600)
    1144         182 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1145             : 
    1146             :     /*
    1147             :      * Quote all identifiers, if requested.
    1148             :      */
    1149         182 :     if (quote_all_identifiers && AH->remoteVersion >= 90100)
    1150          12 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1151             : 
    1152             :     /*
    1153             :      * Adjust row-security mode, if supported.
    1154             :      */
    1155         182 :     if (AH->remoteVersion >= 90500)
    1156             :     {
    1157         182 :         if (dopt->enable_row_security)
    1158           0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1159             :         else
    1160         182 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1161             :     }
    1162             : 
    1163             :     /*
    1164             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1165             :      */
    1166         182 :     ExecuteSqlStatement(AH, "BEGIN");
    1167         182 :     if (AH->remoteVersion >= 90100)
    1168             :     {
    1169             :         /*
    1170             :          * To support the combination of serializable_deferrable with the jobs
    1171             :          * option we use REPEATABLE READ for the worker connections that are
    1172             :          * passed a snapshot.  As long as the snapshot is acquired in a
    1173             :          * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1174             :          * REPEATABLE READ transaction provides the appropriate integrity
    1175             :          * guarantees.  This is a kluge, but safe for back-patching.
    1176             :          */
    1177         182 :         if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1178           0 :             ExecuteSqlStatement(AH,
    1179             :                                 "SET TRANSACTION ISOLATION LEVEL "
    1180             :                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1181             :         else
    1182         182 :             ExecuteSqlStatement(AH,
    1183             :                                 "SET TRANSACTION ISOLATION LEVEL "
    1184             :                                 "REPEATABLE READ, READ ONLY");
    1185             :     }
    1186             :     else
    1187             :     {
    1188           0 :         ExecuteSqlStatement(AH,
    1189             :                             "SET TRANSACTION ISOLATION LEVEL "
    1190             :                             "SERIALIZABLE, READ ONLY");
    1191             :     }
    1192             : 
    1193             :     /*
    1194             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1195             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1196             :      * is already set (if the server can handle it) and we should use that.
    1197             :      */
    1198         182 :     if (dumpsnapshot)
    1199           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1200             : 
    1201         182 :     if (AH->sync_snapshot_id)
    1202             :     {
    1203          16 :         PQExpBuffer query = createPQExpBuffer();
    1204             : 
    1205          16 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1206          16 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1207          16 :         ExecuteSqlStatement(AH, query->data);
    1208          16 :         destroyPQExpBuffer(query);
    1209             :     }
    1210         174 :     else if (AH->numWorkers > 1 &&
    1211          16 :              AH->remoteVersion >= 90200 &&
    1212           8 :              !dopt->no_synchronized_snapshots)
    1213             :     {
    1214           8 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1215           0 :             fatal("Synchronized snapshots on standby servers are not supported by this server version.\n"
    1216             :                   "Run with --no-synchronized-snapshots instead if you do not need\n"
    1217             :                   "synchronized snapshots.");
    1218             : 
    1219             : 
    1220           8 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1221             :     }
    1222         182 : }
    1223             : 
    1224             : /* Set up connection for a parallel worker process */
    1225             : static void
    1226          16 : setupDumpWorker(Archive *AH)
    1227             : {
    1228             :     /*
    1229             :      * We want to re-select all the same values the master connection is
    1230             :      * using.  We'll have inherited directly-usable values in
    1231             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1232             :      * inherited encoding value back to a string to pass to setup_connection.
    1233             :      */
    1234          16 :     setup_connection(AH,
    1235             :                      pg_encoding_to_char(AH->encoding),
    1236             :                      NULL,
    1237             :                      NULL);
    1238          16 : }
    1239             : 
    1240             : static char *
    1241           8 : get_synchronized_snapshot(Archive *fout)
    1242             : {
    1243           8 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1244             :     char       *result;
    1245             :     PGresult   *res;
    1246             : 
    1247           8 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1248           8 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1249           8 :     PQclear(res);
    1250             : 
    1251           8 :     return result;
    1252             : }
    1253             : 
    1254             : static ArchiveFormat
    1255         174 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1256             : {
    1257             :     ArchiveFormat archiveFormat;
    1258             : 
    1259         174 :     *mode = archModeWrite;
    1260             : 
    1261         174 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1262             :     {
    1263             :         /* This is used by pg_dumpall, and is not documented */
    1264          52 :         archiveFormat = archNull;
    1265          52 :         *mode = archModeAppend;
    1266             :     }
    1267         122 :     else if (pg_strcasecmp(format, "c") == 0)
    1268           4 :         archiveFormat = archCustom;
    1269         118 :     else if (pg_strcasecmp(format, "custom") == 0)
    1270          14 :         archiveFormat = archCustom;
    1271         104 :     else if (pg_strcasecmp(format, "d") == 0)
    1272          10 :         archiveFormat = archDirectory;
    1273          94 :     else if (pg_strcasecmp(format, "directory") == 0)
    1274           2 :         archiveFormat = archDirectory;
    1275          92 :     else if (pg_strcasecmp(format, "p") == 0)
    1276          84 :         archiveFormat = archNull;
    1277           8 :     else if (pg_strcasecmp(format, "plain") == 0)
    1278           2 :         archiveFormat = archNull;
    1279           6 :     else if (pg_strcasecmp(format, "t") == 0)
    1280           4 :         archiveFormat = archTar;
    1281           2 :     else if (pg_strcasecmp(format, "tar") == 0)
    1282           0 :         archiveFormat = archTar;
    1283             :     else
    1284           2 :         fatal("invalid output format \"%s\" specified", format);
    1285         172 :     return archiveFormat;
    1286             : }
    1287             : 
    1288             : /*
    1289             :  * Find the OIDs of all schemas matching the given list of patterns,
    1290             :  * and append them to the given OID list.
    1291             :  */
    1292             : static void
    1293         174 : expand_schema_name_patterns(Archive *fout,
    1294             :                             SimpleStringList *patterns,
    1295             :                             SimpleOidList *oids,
    1296             :                             bool strict_names)
    1297             : {
    1298             :     PQExpBuffer query;
    1299             :     PGresult   *res;
    1300             :     SimpleStringListCell *cell;
    1301             :     int         i;
    1302             : 
    1303         174 :     if (patterns->head == NULL)
    1304         160 :         return;                 /* nothing to do */
    1305             : 
    1306          14 :     query = createPQExpBuffer();
    1307             : 
    1308             :     /*
    1309             :      * The loop below runs multiple SELECTs might sometimes result in
    1310             :      * duplicate entries in the OID list, but we don't care.
    1311             :      */
    1312             : 
    1313          26 :     for (cell = patterns->head; cell; cell = cell->next)
    1314             :     {
    1315          14 :         appendPQExpBufferStr(query,
    1316             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1317          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1318             :                               false, NULL, "n.nspname", NULL, NULL);
    1319             : 
    1320          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1321          14 :         if (strict_names && PQntuples(res) == 0)
    1322           2 :             fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1323             : 
    1324          22 :         for (i = 0; i < PQntuples(res); i++)
    1325             :         {
    1326          10 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1327             :         }
    1328             : 
    1329          12 :         PQclear(res);
    1330          12 :         resetPQExpBuffer(query);
    1331             :     }
    1332             : 
    1333          12 :     destroyPQExpBuffer(query);
    1334             : }
    1335             : 
    1336             : /*
    1337             :  * Find the OIDs of all tables matching the given list of patterns,
    1338             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1339             :  * in pg_dumpall.c
    1340             :  */
    1341             : static void
    1342         324 : expand_table_name_patterns(Archive *fout,
    1343             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1344             :                            bool strict_names)
    1345             : {
    1346             :     PQExpBuffer query;
    1347             :     PGresult   *res;
    1348             :     SimpleStringListCell *cell;
    1349             :     int         i;
    1350             : 
    1351         324 :     if (patterns->head == NULL)
    1352         312 :         return;                 /* nothing to do */
    1353             : 
    1354          12 :     query = createPQExpBuffer();
    1355             : 
    1356             :     /*
    1357             :      * this might sometimes result in duplicate entries in the OID list, but
    1358             :      * we don't care.
    1359             :      */
    1360             : 
    1361          24 :     for (cell = patterns->head; cell; cell = cell->next)
    1362             :     {
    1363             :         /*
    1364             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1365             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1366             :          * search_path argument.
    1367             :          */
    1368          14 :         appendPQExpBuffer(query,
    1369             :                           "SELECT c.oid"
    1370             :                           "\nFROM pg_catalog.pg_class c"
    1371             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1372             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1373             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1374             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1375             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1376             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1377             :                           RELKIND_PARTITIONED_TABLE);
    1378          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1379             :                               false, "n.nspname", "c.relname", NULL,
    1380             :                               "pg_catalog.pg_table_is_visible(c.oid)");
    1381             : 
    1382          14 :         ExecuteSqlStatement(fout, "RESET search_path");
    1383          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1384          14 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1385             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1386          14 :         if (strict_names && PQntuples(res) == 0)
    1387           2 :             fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1388             : 
    1389          22 :         for (i = 0; i < PQntuples(res); i++)
    1390             :         {
    1391          10 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1392             :         }
    1393             : 
    1394          12 :         PQclear(res);
    1395          12 :         resetPQExpBuffer(query);
    1396             :     }
    1397             : 
    1398          10 :     destroyPQExpBuffer(query);
    1399             : }
    1400             : 
    1401             : /*
    1402             :  * checkExtensionMembership
    1403             :  *      Determine whether object is an extension member, and if so,
    1404             :  *      record an appropriate dependency and set the object's dump flag.
    1405             :  *
    1406             :  * It's important to call this for each object that could be an extension
    1407             :  * member.  Generally, we integrate this with determining the object's
    1408             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1409             :  *
    1410             :  * Returns true if object is an extension member, else false.
    1411             :  */
    1412             : static bool
    1413      298140 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1414             : {
    1415      298140 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1416             : 
    1417      298140 :     if (ext == NULL)
    1418      297552 :         return false;
    1419             : 
    1420         588 :     dobj->ext_member = true;
    1421             : 
    1422             :     /* Record dependency so that getDependencies needn't deal with that */
    1423         588 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1424             : 
    1425             :     /*
    1426             :      * In 9.6 and above, mark the member object to have any non-initial ACL,
    1427             :      * policies, and security labels dumped.
    1428             :      *
    1429             :      * Note that any initial ACLs (see pg_init_privs) will be removed when we
    1430             :      * extract the information about the object.  We don't provide support for
    1431             :      * initial policies and security labels and it seems unlikely for those to
    1432             :      * ever exist, but we may have to revisit this later.
    1433             :      *
    1434             :      * Prior to 9.6, we do not include any extension member components.
    1435             :      *
    1436             :      * In binary upgrades, we still dump all components of the members
    1437             :      * individually, since the idea is to exactly reproduce the database
    1438             :      * contents rather than replace the extension contents with something
    1439             :      * different.
    1440             :      */
    1441         588 :     if (fout->dopt->binary_upgrade)
    1442          88 :         dobj->dump = ext->dobj.dump;
    1443             :     else
    1444             :     {
    1445         500 :         if (fout->remoteVersion < 90600)
    1446           0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1447             :         else
    1448         500 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
    1449             :                                                     DUMP_COMPONENT_SECLABEL |
    1450             :                                                     DUMP_COMPONENT_POLICY);
    1451             :     }
    1452             : 
    1453         588 :     return true;
    1454             : }
    1455             : 
    1456             : /*
    1457             :  * selectDumpableNamespace: policy-setting subroutine
    1458             :  *      Mark a namespace as to be dumped or not
    1459             :  */
    1460             : static void
    1461        1252 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1462             : {
    1463             :     /*
    1464             :      * If specific tables are being dumped, do not dump any complete
    1465             :      * namespaces. If specific namespaces are being dumped, dump just those
    1466             :      * namespaces. Otherwise, dump all non-system namespaces.
    1467             :      */
    1468        1252 :     if (table_include_oids.head != NULL)
    1469          32 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1470        1220 :     else if (schema_include_oids.head != NULL)
    1471          64 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1472          64 :             simple_oid_list_member(&schema_include_oids,
    1473             :                                    nsinfo->dobj.catId.oid) ?
    1474          64 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1475        2312 :     else if (fout->remoteVersion >= 90600 &&
    1476        1156 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1477             :     {
    1478             :         /*
    1479             :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    1480             :          * they are interesting (and not the original ACLs which were set at
    1481             :          * initdb time, see pg_init_privs).
    1482             :          */
    1483         146 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1484             :     }
    1485        1478 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1486         468 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    1487             :     {
    1488             :         /* Other system schemas don't get dumped */
    1489         688 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1490             :     }
    1491         322 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    1492             :     {
    1493             :         /*
    1494             :          * The public schema is a strange beast that sits in a sort of
    1495             :          * no-mans-land between being a system object and a user object.  We
    1496             :          * don't want to dump creation or comment commands for it, because
    1497             :          * that complicates matters for non-superuser use of pg_dump.  But we
    1498             :          * should dump any ACL changes that have occurred for it, and of
    1499             :          * course we should dump contained objects.
    1500             :          */
    1501         140 :         nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1502         140 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    1503             :     }
    1504             :     else
    1505         182 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1506             : 
    1507             :     /*
    1508             :      * In any case, a namespace can be excluded by an exclusion switch
    1509             :      */
    1510        1728 :     if (nsinfo->dobj.dump_contains &&
    1511         476 :         simple_oid_list_member(&schema_exclude_oids,
    1512             :                                nsinfo->dobj.catId.oid))
    1513           2 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1514             : 
    1515             :     /*
    1516             :      * If the schema belongs to an extension, allow extension membership to
    1517             :      * override the dump decision for the schema itself.  However, this does
    1518             :      * not change dump_contains, so this won't change what we do with objects
    1519             :      * within the schema.  (If they belong to the extension, they'll get
    1520             :      * suppressed by it, otherwise not.)
    1521             :      */
    1522        1252 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    1523        1252 : }
    1524             : 
    1525             : /*
    1526             :  * selectDumpableTable: policy-setting subroutine
    1527             :  *      Mark a table as to be dumped or not
    1528             :  */
    1529             : static void
    1530       35780 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    1531             : {
    1532       35780 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    1533         224 :         return;                 /* extension membership overrides all else */
    1534             : 
    1535             :     /*
    1536             :      * If specific tables are being dumped, dump just those tables; else, dump
    1537             :      * according to the parent namespace's dump flag.
    1538             :      */
    1539       35556 :     if (table_include_oids.head != NULL)
    1540        1760 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    1541             :                                                    tbinfo->dobj.catId.oid) ?
    1542         880 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1543             :     else
    1544       34676 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    1545             : 
    1546             :     /*
    1547             :      * In any case, a table can be excluded by an exclusion switch
    1548             :      */
    1549       59048 :     if (tbinfo->dobj.dump &&
    1550       23492 :         simple_oid_list_member(&table_exclude_oids,
    1551             :                                tbinfo->dobj.catId.oid))
    1552           2 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1553             : }
    1554             : 
    1555             : /*
    1556             :  * selectDumpableType: policy-setting subroutine
    1557             :  *      Mark a type as to be dumped or not
    1558             :  *
    1559             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    1560             :  * special type code to facilitate sorting into the desired order.  (We don't
    1561             :  * want to consider those to be ordinary types because that would bring tables
    1562             :  * up into the datatype part of the dump order.)  We still set the object's
    1563             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    1564             :  * need it so that casts involving such types will be dumped correctly -- see
    1565             :  * dumpCast.  This means the flag should be set the same as for the underlying
    1566             :  * object (the table or base type).
    1567             :  */
    1568             : static void
    1569       75858 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    1570             : {
    1571             :     /* skip complex types, except for standalone composite types */
    1572      118950 :     if (OidIsValid(tyinfo->typrelid) &&
    1573       43092 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    1574             :     {
    1575       42906 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    1576             : 
    1577       42906 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    1578       42906 :         if (tytable != NULL)
    1579       35394 :             tyinfo->dobj.dump = tytable->dobj.dump;
    1580             :         else
    1581        7512 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1582       42906 :         return;
    1583             :     }
    1584             : 
    1585             :     /* skip auto-generated array types */
    1586       32952 :     if (tyinfo->isArray)
    1587             :     {
    1588       17262 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    1589             : 
    1590             :         /*
    1591             :          * Fall through to set the dump flag; we assume that the subsequent
    1592             :          * rules will do the same thing as they would for the array's base
    1593             :          * type.  (We cannot reliably look up the base type here, since
    1594             :          * getTypes may not have processed it yet.)
    1595             :          */
    1596             :     }
    1597             : 
    1598       32952 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    1599          32 :         return;                 /* extension membership overrides all else */
    1600             : 
    1601             :     /* Dump based on if the contents of the namespace are being dumped */
    1602       32920 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    1603             : }
    1604             : 
    1605             : /*
    1606             :  * selectDumpableDefaultACL: policy-setting subroutine
    1607             :  *      Mark a default ACL as to be dumped or not
    1608             :  *
    1609             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    1610             :  * Otherwise dump if we are dumping "everything".  Note that dataOnly
    1611             :  * and aclsSkip are checked separately.
    1612             :  */
    1613             : static void
    1614         174 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    1615             : {
    1616             :     /* Default ACLs can't be extension members */
    1617             : 
    1618         174 :     if (dinfo->dobj.namespace)
    1619             :         /* default ACLs are considered part of the namespace */
    1620          58 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    1621             :     else
    1622         232 :         dinfo->dobj.dump = dopt->include_everything ?
    1623         116 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1624         174 : }
    1625             : 
    1626             : /*
    1627             :  * selectDumpableCast: policy-setting subroutine
    1628             :  *      Mark a cast as to be dumped or not
    1629             :  *
    1630             :  * Casts do not belong to any particular namespace (since they haven't got
    1631             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    1632             :  * casts from built-in ones, we must resort to checking whether the cast's
    1633             :  * OID is in the range reserved for initdb.
    1634             :  */
    1635             : static void
    1636       33790 : selectDumpableCast(CastInfo *cast, Archive *fout)
    1637             : {
    1638       33790 :     if (checkExtensionMembership(&cast->dobj, fout))
    1639           0 :         return;                 /* extension membership overrides all else */
    1640             : 
    1641             :     /*
    1642             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    1643             :      * support ACLs currently.
    1644             :      */
    1645       33790 :     if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    1646       33696 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    1647             :     else
    1648         188 :         cast->dobj.dump = fout->dopt->include_everything ?
    1649          94 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1650             : }
    1651             : 
    1652             : /*
    1653             :  * selectDumpableProcLang: policy-setting subroutine
    1654             :  *      Mark a procedural language as to be dumped or not
    1655             :  *
    1656             :  * Procedural languages do not belong to any particular namespace.  To
    1657             :  * identify built-in languages, we must resort to checking whether the
    1658             :  * language's OID is in the range reserved for initdb.
    1659             :  */
    1660             : static void
    1661         214 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    1662             : {
    1663         214 :     if (checkExtensionMembership(&plang->dobj, fout))
    1664         156 :         return;                 /* extension membership overrides all else */
    1665             : 
    1666             :     /*
    1667             :      * Only include procedural languages when we are dumping everything.
    1668             :      *
    1669             :      * For from-initdb procedural languages, only include ACLs, as we do for
    1670             :      * the pg_catalog namespace.  We need this because procedural languages do
    1671             :      * not live in any namespace.
    1672             :      */
    1673          58 :     if (!fout->dopt->include_everything)
    1674          12 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    1675             :     else
    1676             :     {
    1677          46 :         if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    1678           0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    1679           0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    1680             :         else
    1681          46 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    1682             :     }
    1683             : }
    1684             : 
    1685             : /*
    1686             :  * selectDumpableAccessMethod: policy-setting subroutine
    1687             :  *      Mark an access method as to be dumped or not
    1688             :  *
    1689             :  * Access methods do not belong to any particular namespace.  To identify
    1690             :  * built-in access methods, we must resort to checking whether the
    1691             :  * method's OID is in the range reserved for initdb.
    1692             :  */
    1693             : static void
    1694        1246 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    1695             : {
    1696        1246 :     if (checkExtensionMembership(&method->dobj, fout))
    1697          32 :         return;                 /* extension membership overrides all else */
    1698             : 
    1699             :     /*
    1700             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    1701             :      * they do not support ACLs currently.
    1702             :      */
    1703        1214 :     if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    1704        1092 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    1705             :     else
    1706         244 :         method->dobj.dump = fout->dopt->include_everything ?
    1707         122 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1708             : }
    1709             : 
    1710             : /*
    1711             :  * selectDumpableExtension: policy-setting subroutine
    1712             :  *      Mark an extension as to be dumped or not
    1713             :  *
    1714             :  * Built-in extensions should be skipped except for checking ACLs, since we
    1715             :  * assume those will already be installed in the target database.  We identify
    1716             :  * such extensions by their having OIDs in the range reserved for initdb.
    1717             :  * We dump all user-added extensions by default, or none of them if
    1718             :  * include_everything is false (i.e., a --schema or --table switch was given).
    1719             :  */
    1720             : static void
    1721         190 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    1722             : {
    1723             :     /*
    1724             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    1725             :      * change permissions on their member objects, if they wish to, and have
    1726             :      * those changes preserved.
    1727             :      */
    1728         190 :     if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    1729         158 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    1730             :     else
    1731          32 :         extinfo->dobj.dump = extinfo->dobj.dump_contains =
    1732          32 :             dopt->include_everything ? DUMP_COMPONENT_ALL :
    1733             :             DUMP_COMPONENT_NONE;
    1734         190 : }
    1735             : 
    1736             : /*
    1737             :  * selectDumpablePublicationTable: policy-setting subroutine
    1738             :  *      Mark a publication table as to be dumped or not
    1739             :  *
    1740             :  * Publication tables have schemas, but those are ignored in decision making,
    1741             :  * because publications are only dumped when we are dumping everything.
    1742             :  */
    1743             : static void
    1744          98 : selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
    1745             : {
    1746          98 :     if (checkExtensionMembership(dobj, fout))
    1747           0 :         return;                 /* extension membership overrides all else */
    1748             : 
    1749         196 :     dobj->dump = fout->dopt->include_everything ?
    1750          98 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1751             : }
    1752             : 
    1753             : /*
    1754             :  * selectDumpableObject: policy-setting subroutine
    1755             :  *      Mark a generic dumpable object as to be dumped or not
    1756             :  *
    1757             :  * Use this only for object types without a special-case routine above.
    1758             :  */
    1759             : static void
    1760      192808 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    1761             : {
    1762      192808 :     if (checkExtensionMembership(dobj, fout))
    1763         112 :         return;                 /* extension membership overrides all else */
    1764             : 
    1765             :     /*
    1766             :      * Default policy is to dump if parent namespace is dumpable, or for
    1767             :      * non-namespace-associated items, dump if we're dumping "everything".
    1768             :      */
    1769      192696 :     if (dobj->namespace)
    1770      192276 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    1771             :     else
    1772         840 :         dobj->dump = fout->dopt->include_everything ?
    1773         420 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1774             : }
    1775             : 
    1776             : /*
    1777             :  *  Dump a table's contents for loading using the COPY command
    1778             :  *  - this routine is called by the Archiver when it wants the table
    1779             :  *    to be dumped.
    1780             :  */
    1781             : 
    1782             : static int
    1783        2436 : dumpTableData_copy(Archive *fout, void *dcontext)
    1784             : {
    1785        2436 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    1786        2436 :     TableInfo  *tbinfo = tdinfo->tdtable;
    1787        2436 :     const char *classname = tbinfo->dobj.name;
    1788        2436 :     PQExpBuffer q = createPQExpBuffer();
    1789             : 
    1790             :     /*
    1791             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    1792             :      * which uses it already.
    1793             :      */
    1794        2436 :     PQExpBuffer clistBuf = createPQExpBuffer();
    1795        2436 :     PGconn     *conn = GetConnection(fout);
    1796             :     PGresult   *res;
    1797             :     int         ret;
    1798             :     char       *copybuf;
    1799             :     const char *column_list;
    1800             : 
    1801        2436 :     pg_log_info("dumping contents of table \"%s.%s\"",
    1802             :                 tbinfo->dobj.namespace->dobj.name, classname);
    1803             : 
    1804             :     /*
    1805             :      * Specify the column list explicitly so that we have no possibility of
    1806             :      * retrieving data in the wrong column order.  (The default column
    1807             :      * ordering of COPY will not be what we want in certain corner cases
    1808             :      * involving ADD COLUMN and inheritance.)
    1809             :      */
    1810        2436 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    1811             : 
    1812        2436 :     if (tdinfo->filtercond)
    1813             :     {
    1814             :         /* Note: this syntax is only supported in 8.2 and up */
    1815           0 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    1816             :         /* klugery to get rid of parens in column list */
    1817           0 :         if (strlen(column_list) > 2)
    1818             :         {
    1819           0 :             appendPQExpBufferStr(q, column_list + 1);
    1820           0 :             q->data[q->len - 1] = ' ';
    1821             :         }
    1822             :         else
    1823           0 :             appendPQExpBufferStr(q, "* ");
    1824           0 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    1825           0 :                           fmtQualifiedDumpable(tbinfo),
    1826             :                           tdinfo->filtercond);
    1827             :     }
    1828             :     else
    1829             :     {
    1830        2436 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    1831        2436 :                           fmtQualifiedDumpable(tbinfo),
    1832             :                           column_list);
    1833             :     }
    1834        2436 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    1835        2436 :     PQclear(res);
    1836        2436 :     destroyPQExpBuffer(clistBuf);
    1837             : 
    1838             :     for (;;)
    1839             :     {
    1840     2908484 :         ret = PQgetCopyData(conn, &copybuf, 0);
    1841             : 
    1842     1455460 :         if (ret < 0)
    1843        2436 :             break;              /* done or error */
    1844             : 
    1845     1453024 :         if (copybuf)
    1846             :         {
    1847     1453024 :             WriteData(fout, copybuf, ret);
    1848     1453024 :             PQfreemem(copybuf);
    1849             :         }
    1850             : 
    1851             :         /* ----------
    1852             :          * THROTTLE:
    1853             :          *
    1854             :          * There was considerable discussion in late July, 2000 regarding
    1855             :          * slowing down pg_dump when backing up large tables. Users with both
    1856             :          * slow & fast (multi-processor) machines experienced performance
    1857             :          * degradation when doing a backup.
    1858             :          *
    1859             :          * Initial attempts based on sleeping for a number of ms for each ms
    1860             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    1861             :          * implementation was suggested. The latter failed because the loop
    1862             :          * was too tight. Finally, the following was implemented:
    1863             :          *
    1864             :          * If throttle is non-zero, then
    1865             :          *      See how long since the last sleep.
    1866             :          *      Work out how long to sleep (based on ratio).
    1867             :          *      If sleep is more than 100ms, then
    1868             :          *          sleep
    1869             :          *          reset timer
    1870             :          *      EndIf
    1871             :          * EndIf
    1872             :          *
    1873             :          * where the throttle value was the number of ms to sleep per ms of
    1874             :          * work. The calculation was done in each loop.
    1875             :          *
    1876             :          * Most of the hard work is done in the backend, and this solution
    1877             :          * still did not work particularly well: on slow machines, the ratio
    1878             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    1879             :          * multi-processor machines, it had little or no effect, for reasons
    1880             :          * that were unclear.
    1881             :          *
    1882             :          * Further discussion ensued, and the proposal was dropped.
    1883             :          *
    1884             :          * For those people who want this feature, it can be implemented using
    1885             :          * gettimeofday in each loop, calculating the time since last sleep,
    1886             :          * multiplying that by the sleep ratio, then if the result is more
    1887             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    1888             :          * function to sleep for a subsecond period ie.
    1889             :          *
    1890             :          * select(0, NULL, NULL, NULL, &tvi);
    1891             :          *
    1892             :          * This will return after the interval specified in the structure tvi.
    1893             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    1894             :          * ----------
    1895             :          */
    1896             :     }
    1897        2436 :     archprintf(fout, "\\.\n\n\n");
    1898             : 
    1899        2436 :     if (ret == -2)
    1900             :     {
    1901             :         /* copy data transfer failed */
    1902           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    1903           0 :         pg_log_error("Error message from server: %s", PQerrorMessage(conn));
    1904           0 :         pg_log_error("The command was: %s", q->data);
    1905           0 :         exit_nicely(1);
    1906             :     }
    1907             : 
    1908             :     /* Check command status and return to normal libpq state */
    1909        2436 :     res = PQgetResult(conn);
    1910        2436 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    1911             :     {
    1912           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    1913           0 :         pg_log_error("Error message from server: %s", PQerrorMessage(conn));
    1914           0 :         pg_log_error("The command was: %s", q->data);
    1915           0 :         exit_nicely(1);
    1916             :     }
    1917        2436 :     PQclear(res);
    1918             : 
    1919             :     /* Do this to ensure we've pumped libpq back to idle state */
    1920        2436 :     if (PQgetResult(conn) != NULL)
    1921           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    1922             :                        classname);
    1923             : 
    1924        2436 :     destroyPQExpBuffer(q);
    1925        2436 :     return 1;
    1926             : }
    1927             : 
    1928             : /*
    1929             :  * Dump table data using INSERT commands.
    1930             :  *
    1931             :  * Caution: when we restore from an archive file direct to database, the
    1932             :  * INSERT commands emitted by this function have to be parsed by
    1933             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    1934             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    1935             :  */
    1936             : static int
    1937          34 : dumpTableData_insert(Archive *fout, void *dcontext)
    1938             : {
    1939          34 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    1940          34 :     TableInfo  *tbinfo = tdinfo->tdtable;
    1941          34 :     DumpOptions *dopt = fout->dopt;
    1942          34 :     PQExpBuffer q = createPQExpBuffer();
    1943          34 :     PQExpBuffer insertStmt = NULL;
    1944             :     PGresult   *res;
    1945             :     int         nfields;
    1946          34 :     int         rows_per_statement = dopt->dump_inserts;
    1947          34 :     int         rows_this_statement = 0;
    1948             : 
    1949          34 :     appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
    1950             :                       "SELECT * FROM ONLY %s",
    1951          34 :                       fmtQualifiedDumpable(tbinfo));
    1952          34 :     if (tdinfo->filtercond)
    1953           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    1954             : 
    1955          34 :     ExecuteSqlStatement(fout, q->data);
    1956             : 
    1957             :     while (1)
    1958             :     {
    1959          66 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    1960             :                               PGRES_TUPLES_OK);
    1961          50 :         nfields = PQnfields(res);
    1962             : 
    1963             :         /*
    1964             :          * First time through, we build as much of the INSERT statement as
    1965             :          * possible in "insertStmt", which we can then just print for each
    1966             :          * statement. If the table happens to have zero columns then this will
    1967             :          * be a complete statement, otherwise it will end in "VALUES" and be
    1968             :          * ready to have the row's column values printed.
    1969             :          */
    1970          50 :         if (insertStmt == NULL)
    1971             :         {
    1972             :             TableInfo  *targettab;
    1973             : 
    1974          34 :             insertStmt = createPQExpBuffer();
    1975             : 
    1976             :             /*
    1977             :              * When load-via-partition-root is set, get the root table name
    1978             :              * for the partition table, so that we can reload data through the
    1979             :              * root table.
    1980             :              */
    1981          34 :             if (dopt->load_via_partition_root && tbinfo->ispartition)
    1982           0 :                 targettab = getRootTableInfo(tbinfo);
    1983             :             else
    1984          34 :                 targettab = tbinfo;
    1985             : 
    1986          34 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    1987          34 :                               fmtQualifiedDumpable(targettab));
    1988             : 
    1989             :             /* corner case for zero-column table */
    1990          34 :             if (nfields == 0)
    1991             :             {
    1992           8 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    1993             :             }
    1994             :             else
    1995             :             {
    1996             :                 /* append the list of column names if required */
    1997          26 :                 if (dopt->column_inserts)
    1998             :                 {
    1999          24 :                     appendPQExpBufferChar(insertStmt, '(');
    2000          82 :                     for (int field = 0; field < nfields; field++)
    2001             :                     {
    2002          58 :                         if (field > 0)
    2003          34 :                             appendPQExpBufferStr(insertStmt, ", ");
    2004          58 :                         appendPQExpBufferStr(insertStmt,
    2005          58 :                                              fmtId(PQfname(res, field)));
    2006             :                     }
    2007          24 :                     appendPQExpBufferStr(insertStmt, ") ");
    2008             :                 }
    2009             : 
    2010          26 :                 if (tbinfo->needs_override)
    2011           2 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2012             : 
    2013          26 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2014             :             }
    2015             :         }
    2016             : 
    2017         126 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2018             :         {
    2019             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2020          76 :             if (rows_this_statement == 0)
    2021          64 :                 archputs(insertStmt->data, fout);
    2022             : 
    2023             :             /*
    2024             :              * If it is zero-column table then we've already written the
    2025             :              * complete statement, which will mean we've disobeyed
    2026             :              * --rows-per-insert when it's set greater than 1.  We do support
    2027             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2028             :              * UNION ALL ... but that's non-standard so we should avoid it
    2029             :              * given that using INSERTs is mostly only ever needed for
    2030             :              * cross-database exports.
    2031             :              */
    2032          76 :             if (nfields == 0)
    2033           8 :                 continue;
    2034             : 
    2035             :             /* Emit a row heading */
    2036          68 :             if (rows_per_statement == 1)
    2037          50 :                 archputs(" (", fout);
    2038          18 :             else if (rows_this_statement > 0)
    2039          12 :                 archputs(",\n\t(", fout);
    2040             :             else
    2041           6 :                 archputs("\n\t(", fout);
    2042             : 
    2043         272 :             for (int field = 0; field < nfields; field++)
    2044             :             {
    2045         204 :                 if (field > 0)
    2046         136 :                     archputs(", ", fout);
    2047         204 :                 if (tbinfo->attgenerated[field])
    2048             :                 {
    2049           0 :                     archputs("DEFAULT", fout);
    2050           0 :                     continue;
    2051             :                 }
    2052         204 :                 if (PQgetisnull(res, tuple, field))
    2053             :                 {
    2054         110 :                     archputs("NULL", fout);
    2055         110 :                     continue;
    2056             :                 }
    2057             : 
    2058             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2059          94 :                 switch (PQftype(res, field))
    2060             :                 {
    2061             :                     case INT2OID:
    2062             :                     case INT4OID:
    2063             :                     case INT8OID:
    2064             :                     case OIDOID:
    2065             :                     case FLOAT4OID:
    2066             :                     case FLOAT8OID:
    2067             :                     case NUMERICOID:
    2068             :                         {
    2069             :                             /*
    2070             :                              * These types are printed without quotes unless
    2071             :                              * they contain values that aren't accepted by the
    2072             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2073             :                              * strtod() and friends might accept NaN, so we
    2074             :                              * can't use that to test.
    2075             :                              *
    2076             :                              * In reality we only need to defend against
    2077             :                              * infinity and NaN, so we need not get too crazy
    2078             :                              * about pattern matching here.
    2079             :                              */
    2080          68 :                             const char *s = PQgetvalue(res, tuple, field);
    2081             : 
    2082          68 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2083          66 :                                 archputs(s, fout);
    2084             :                             else
    2085           2 :                                 archprintf(fout, "'%s'", s);
    2086             :                         }
    2087          68 :                         break;
    2088             : 
    2089             :                     case BITOID:
    2090             :                     case VARBITOID:
    2091           2 :                         archprintf(fout, "B'%s'",
    2092             :                                    PQgetvalue(res, tuple, field));
    2093           2 :                         break;
    2094             : 
    2095             :                     case BOOLOID:
    2096           4 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2097           2 :                             archputs("true", fout);
    2098             :                         else
    2099           2 :                             archputs("false", fout);
    2100           4 :                         break;
    2101             : 
    2102             :                     default:
    2103             :                         /* All other types are printed as string literals. */
    2104          20 :                         resetPQExpBuffer(q);
    2105          20 :                         appendStringLiteralAH(q,
    2106             :                                               PQgetvalue(res, tuple, field),
    2107             :                                               fout);
    2108          20 :                         archputs(q->data, fout);
    2109          20 :                         break;
    2110             :                 }
    2111             :             }
    2112             : 
    2113             :             /* Terminate the row ... */
    2114          68 :             archputs(")", fout);
    2115             : 
    2116             :             /* ... and the statement, if the target no. of rows is reached */
    2117          68 :             if (++rows_this_statement >= rows_per_statement)
    2118             :             {
    2119          54 :                 if (dopt->do_nothing)
    2120           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2121             :                 else
    2122          54 :                     archputs(";\n", fout);
    2123             :                 /* Reset the row counter */
    2124          54 :                 rows_this_statement = 0;
    2125             :             }
    2126             :         }
    2127             : 
    2128          50 :         if (PQntuples(res) <= 0)
    2129             :         {
    2130          34 :             PQclear(res);
    2131          34 :             break;
    2132             :         }
    2133          16 :         PQclear(res);
    2134             :     }
    2135             : 
    2136             :     /* Terminate any statements that didn't make the row count. */
    2137          34 :     if (rows_this_statement > 0)
    2138             :     {
    2139           2 :         if (dopt->do_nothing)
    2140           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2141             :         else
    2142           2 :             archputs(";\n", fout);
    2143             :     }
    2144             : 
    2145          34 :     archputs("\n\n", fout);
    2146             : 
    2147          34 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2148             : 
    2149          34 :     destroyPQExpBuffer(q);
    2150          34 :     if (insertStmt != NULL)
    2151          34 :         destroyPQExpBuffer(insertStmt);
    2152             : 
    2153          34 :     return 1;
    2154             : }
    2155             : 
    2156             : /*
    2157             :  * getRootTableInfo:
    2158             :  *     get the root TableInfo for the given partition table.
    2159             :  */
    2160             : static TableInfo *
    2161           0 : getRootTableInfo(TableInfo *tbinfo)
    2162             : {
    2163             :     TableInfo  *parentTbinfo;
    2164             : 
    2165             :     Assert(tbinfo->ispartition);
    2166             :     Assert(tbinfo->numParents == 1);
    2167             : 
    2168           0 :     parentTbinfo = tbinfo->parents[0];
    2169           0 :     while (parentTbinfo->ispartition)
    2170             :     {
    2171             :         Assert(parentTbinfo->numParents == 1);
    2172           0 :         parentTbinfo = parentTbinfo->parents[0];
    2173             :     }
    2174             : 
    2175           0 :     return parentTbinfo;
    2176             : }
    2177             : 
    2178             : /*
    2179             :  * dumpTableData -
    2180             :  *    dump the contents of a single table
    2181             :  *
    2182             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2183             :  */
    2184             : static void
    2185        2534 : dumpTableData(Archive *fout, TableDataInfo *tdinfo)
    2186             : {
    2187        2534 :     DumpOptions *dopt = fout->dopt;
    2188        2534 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2189        2534 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2190        2534 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2191             :     DataDumperPtr dumpFn;
    2192             :     char       *copyStmt;
    2193             :     const char *copyFrom;
    2194             : 
    2195        2534 :     if (!dopt->dump_inserts)
    2196             :     {
    2197             :         /* Dump/restore using COPY */
    2198        2500 :         dumpFn = dumpTableData_copy;
    2199             : 
    2200             :         /*
    2201             :          * When load-via-partition-root is set, get the root table name for
    2202             :          * the partition table, so that we can reload data through the root
    2203             :          * table.
    2204             :          */
    2205        2500 :         if (dopt->load_via_partition_root && tbinfo->ispartition)
    2206           0 :         {
    2207             :             TableInfo  *parentTbinfo;
    2208             : 
    2209           0 :             parentTbinfo = getRootTableInfo(tbinfo);
    2210           0 :             copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2211             :         }
    2212             :         else
    2213        2500 :             copyFrom = fmtQualifiedDumpable(tbinfo);
    2214             : 
    2215             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2216        2500 :         appendPQExpBuffer(copyBuf, "COPY %s ",
    2217             :                           copyFrom);
    2218        2500 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2219             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2220        2500 :         copyStmt = copyBuf->data;
    2221             :     }
    2222             :     else
    2223             :     {
    2224             :         /* Restore using INSERT */
    2225          34 :         dumpFn = dumpTableData_insert;
    2226          34 :         copyStmt = NULL;
    2227             :     }
    2228             : 
    2229             :     /*
    2230             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2231             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2232             :      * See comments for BuildArchiveDependencies.
    2233             :      */
    2234        2534 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2235             :     {
    2236             :         TocEntry   *te;
    2237             : 
    2238        2534 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2239        2534 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2240             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2241             :                                        .owner = tbinfo->rolname,
    2242             :                                        .description = "TABLE DATA",
    2243             :                                        .section = SECTION_DATA,
    2244             :                                        .copyStmt = copyStmt,
    2245             :                                        .deps = &(tbinfo->dobj.dumpId),
    2246             :                                        .nDeps = 1,
    2247             :                                        .dumpFn = dumpFn,
    2248             :                                        .dumpArg = tdinfo));
    2249             : 
    2250             :         /*
    2251             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2252             :          * and want to order dump jobs by table size.  We choose to measure
    2253             :          * dataLength in table pages during dump, so no scaling is needed.
    2254             :          * However, relpages is declared as "integer" in pg_class, and hence
    2255             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2256             :          * Cast so that we get the right interpretation of table sizes
    2257             :          * exceeding INT_MAX pages.
    2258             :          */
    2259        2534 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2260             :     }
    2261             : 
    2262        2534 :     destroyPQExpBuffer(copyBuf);
    2263        2534 :     destroyPQExpBuffer(clistBuf);
    2264        2534 : }
    2265             : 
    2266             : /*
    2267             :  * refreshMatViewData -
    2268             :  *    load or refresh the contents of a single materialized view
    2269             :  *
    2270             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2271             :  * statement.
    2272             :  */
    2273             : static void
    2274         336 : refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
    2275             : {
    2276         336 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2277             :     PQExpBuffer q;
    2278             : 
    2279             :     /* If the materialized view is not flagged as populated, skip this. */
    2280         336 :     if (!tbinfo->relispopulated)
    2281          88 :         return;
    2282             : 
    2283         248 :     q = createPQExpBuffer();
    2284             : 
    2285         248 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2286         248 :                       fmtQualifiedDumpable(tbinfo));
    2287             : 
    2288         248 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2289         248 :         ArchiveEntry(fout,
    2290             :                      tdinfo->dobj.catId, /* catalog ID */
    2291             :                      tdinfo->dobj.dumpId,    /* dump ID */
    2292         248 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2293             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2294             :                                   .owner = tbinfo->rolname,
    2295             :                                   .description = "MATERIALIZED VIEW DATA",
    2296             :                                   .section = SECTION_POST_DATA,
    2297             :                                   .createStmt = q->data,
    2298             :                                   .deps = tdinfo->dobj.dependencies,
    2299             :                                   .nDeps = tdinfo->dobj.nDeps));
    2300             : 
    2301         248 :     destroyPQExpBuffer(q);
    2302             : }
    2303             : 
    2304             : /*
    2305             :  * getTableData -
    2306             :  *    set up dumpable objects representing the contents of tables
    2307             :  */
    2308             : static void
    2309         152 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2310             : {
    2311             :     int         i;
    2312             : 
    2313       34890 :     for (i = 0; i < numTables; i++)
    2314             :     {
    2315       34738 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2316        1292 :             (!relkind || tblinfo[i].relkind == relkind))
    2317        3846 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2318             :     }
    2319         152 : }
    2320             : 
    2321             : /*
    2322             :  * Make a dumpable object for the data of this specific table
    2323             :  *
    2324             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    2325             :  * table data; the "dump" flag in such objects isn't used.
    2326             :  */
    2327             : static void
    2328        3878 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    2329             : {
    2330             :     TableDataInfo *tdinfo;
    2331             : 
    2332             :     /*
    2333             :      * Nothing to do if we already decided to dump the table.  This will
    2334             :      * happen for "config" tables.
    2335             :      */
    2336        3878 :     if (tbinfo->dataObj != NULL)
    2337           2 :         return;
    2338             : 
    2339             :     /* Skip VIEWs (no data to dump) */
    2340        3876 :     if (tbinfo->relkind == RELKIND_VIEW)
    2341         216 :         return;
    2342             :     /* Skip FOREIGN TABLEs (no data to dump) */
    2343        3660 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2344          44 :         return;
    2345             :     /* Skip partitioned tables (data in partitions) */
    2346        3616 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    2347         336 :         return;
    2348             : 
    2349             :     /* Don't dump data in unlogged tables, if so requested */
    2350        3280 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    2351           0 :         dopt->no_unlogged_table_data)
    2352           0 :         return;
    2353             : 
    2354             :     /* Check that the data is not explicitly excluded */
    2355        3280 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    2356             :                                tbinfo->dobj.catId.oid))
    2357           2 :         return;
    2358             : 
    2359             :     /* OK, let's dump it */
    2360        3278 :     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    2361             : 
    2362        3278 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    2363         336 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    2364        2942 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    2365         408 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    2366             :     else
    2367        2534 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    2368             : 
    2369             :     /*
    2370             :      * Note: use tableoid 0 so that this object won't be mistaken for
    2371             :      * something that pg_depend entries apply to.
    2372             :      */
    2373        3278 :     tdinfo->dobj.catId.tableoid = 0;
    2374        3278 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    2375        3278 :     AssignDumpId(&tdinfo->dobj);
    2376        3278 :     tdinfo->dobj.name = tbinfo->dobj.name;
    2377        3278 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    2378        3278 :     tdinfo->tdtable = tbinfo;
    2379        3278 :     tdinfo->filtercond = NULL;   /* might get set later */
    2380        3278 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    2381             : 
    2382        3278 :     tbinfo->dataObj = tdinfo;
    2383             : }
    2384             : 
    2385             : /*
    2386             :  * The refresh for a materialized view must be dependent on the refresh for
    2387             :  * any materialized view that this one is dependent on.
    2388             :  *
    2389             :  * This must be called after all the objects are created, but before they are
    2390             :  * sorted.
    2391             :  */
    2392             : static void
    2393         136 : buildMatViewRefreshDependencies(Archive *fout)
    2394             : {
    2395             :     PQExpBuffer query;
    2396             :     PGresult   *res;
    2397             :     int         ntups,
    2398             :                 i;
    2399             :     int         i_classid,
    2400             :                 i_objid,
    2401             :                 i_refobjid;
    2402             : 
    2403             :     /* No Mat Views before 9.3. */
    2404         136 :     if (fout->remoteVersion < 90300)
    2405           0 :         return;
    2406             : 
    2407         136 :     query = createPQExpBuffer();
    2408             : 
    2409         136 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    2410             :                          "( "
    2411             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    2412             :                          "FROM pg_depend d1 "
    2413             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    2414             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    2415             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    2416             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    2417             :                          "AND d2.objid = r1.oid "
    2418             :                          "AND d2.refobjid <> d1.objid "
    2419             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    2420             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    2421             :                          CppAsString2(RELKIND_VIEW) ") "
    2422             :                          "WHERE d1.classid = 'pg_class'::regclass "
    2423             :                          "UNION "
    2424             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    2425             :                          "FROM w "
    2426             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    2427             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    2428             :                          "AND d3.objid = r3.oid "
    2429             :                          "AND d3.refobjid <> w.refobjid "
    2430             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    2431             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    2432             :                          CppAsString2(RELKIND_VIEW) ") "
    2433             :                          ") "
    2434             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    2435             :                          "FROM w "
    2436             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    2437             : 
    2438         136 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    2439             : 
    2440         136 :     ntups = PQntuples(res);
    2441             : 
    2442         136 :     i_classid = PQfnumber(res, "classid");
    2443         136 :     i_objid = PQfnumber(res, "objid");
    2444         136 :     i_refobjid = PQfnumber(res, "refobjid");
    2445             : 
    2446         472 :     for (i = 0; i < ntups; i++)
    2447             :     {
    2448             :         CatalogId   objId;
    2449             :         CatalogId   refobjId;
    2450             :         DumpableObject *dobj;
    2451             :         DumpableObject *refdobj;
    2452             :         TableInfo  *tbinfo;
    2453             :         TableInfo  *reftbinfo;
    2454             : 
    2455         336 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    2456         336 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    2457         336 :         refobjId.tableoid = objId.tableoid;
    2458         336 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    2459             : 
    2460         336 :         dobj = findObjectByCatalogId(objId);
    2461         336 :         if (dobj == NULL)
    2462          60 :             continue;
    2463             : 
    2464             :         Assert(dobj->objType == DO_TABLE);
    2465         336 :         tbinfo = (TableInfo *) dobj;
    2466             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    2467         336 :         dobj = (DumpableObject *) tbinfo->dataObj;
    2468         336 :         if (dobj == NULL)
    2469          60 :             continue;
    2470             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    2471             : 
    2472         276 :         refdobj = findObjectByCatalogId(refobjId);
    2473         276 :         if (refdobj == NULL)
    2474           0 :             continue;
    2475             : 
    2476             :         Assert(refdobj->objType == DO_TABLE);
    2477         276 :         reftbinfo = (TableInfo *) refdobj;
    2478             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    2479         276 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    2480         276 :         if (refdobj == NULL)
    2481           0 :             continue;
    2482             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    2483             : 
    2484         276 :         addObjectDependency(dobj, refdobj->dumpId);
    2485             : 
    2486         276 :         if (!reftbinfo->relispopulated)
    2487          44 :             tbinfo->relispopulated = false;
    2488             :     }
    2489             : 
    2490         136 :     PQclear(res);
    2491             : 
    2492         136 :     destroyPQExpBuffer(query);
    2493             : }
    2494             : 
    2495             : /*
    2496             :  * getTableDataFKConstraints -
    2497             :  *    add dump-order dependencies reflecting foreign key constraints
    2498             :  *
    2499             :  * This code is executed only in a data-only dump --- in schema+data dumps
    2500             :  * we handle foreign key issues by not creating the FK constraints until
    2501             :  * after the data is loaded.  In a data-only dump, however, we want to
    2502             :  * order the table data objects in such a way that a table's referenced
    2503             :  * tables are restored first.  (In the presence of circular references or
    2504             :  * self-references this may be impossible; we'll detect and complain about
    2505             :  * that during the dependency sorting step.)
    2506             :  */
    2507             : static void
    2508           8 : getTableDataFKConstraints(void)
    2509             : {
    2510             :     DumpableObject **dobjs;
    2511             :     int         numObjs;
    2512             :     int         i;
    2513             : 
    2514             :     /* Search through all the dumpable objects for FK constraints */
    2515           8 :     getDumpableObjects(&dobjs, &numObjs);
    2516       18710 :     for (i = 0; i < numObjs; i++)
    2517             :     {
    2518       18702 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    2519             :         {
    2520           8 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    2521             :             TableInfo  *ftable;
    2522             : 
    2523             :             /* Not interesting unless both tables are to be dumped */
    2524          16 :             if (cinfo->contable == NULL ||
    2525           8 :                 cinfo->contable->dataObj == NULL)
    2526           4 :                 continue;
    2527           4 :             ftable = findTableByOid(cinfo->confrelid);
    2528           8 :             if (ftable == NULL ||
    2529           4 :                 ftable->dataObj == NULL)
    2530           0 :                 continue;
    2531             : 
    2532             :             /*
    2533             :              * Okay, make referencing table's TABLE_DATA object depend on the
    2534             :              * referenced table's TABLE_DATA object.
    2535             :              */
    2536           4 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    2537           4 :                                 ftable->dataObj->dobj.dumpId);
    2538             :         }
    2539             :     }
    2540           8 :     free(dobjs);
    2541           8 : }
    2542             : 
    2543             : 
    2544             : /*
    2545             :  * guessConstraintInheritance:
    2546             :  *  In pre-8.4 databases, we can't tell for certain which constraints
    2547             :  *  are inherited.  We assume a CHECK constraint is inherited if its name
    2548             :  *  matches the name of any constraint in the parent.  Originally this code
    2549             :  *  tried to compare the expression texts, but that can fail for various
    2550             :  *  reasons --- for example, if the parent and child tables are in different
    2551             :  *  schemas, reverse-listing of function calls may produce different text
    2552             :  *  (schema-qualified or not) depending on search path.
    2553             :  *
    2554             :  *  In 8.4 and up we can rely on the conislocal field to decide which
    2555             :  *  constraints must be dumped; much safer.
    2556             :  *
    2557             :  *  This function assumes all conislocal flags were initialized to true.
    2558             :  *  It clears the flag on anything that seems to be inherited.
    2559             :  */
    2560             : static void
    2561           0 : guessConstraintInheritance(TableInfo *tblinfo, int numTables)
    2562             : {
    2563             :     int         i,
    2564             :                 j,
    2565             :                 k;
    2566             : 
    2567           0 :     for (i = 0; i < numTables; i++)
    2568             :     {
    2569           0 :         TableInfo  *tbinfo = &(tblinfo[i]);
    2570             :         int         numParents;
    2571             :         TableInfo **parents;
    2572             :         TableInfo  *parent;
    2573             : 
    2574             :         /* Sequences and views never have parents */
    2575           0 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    2576           0 :             tbinfo->relkind == RELKIND_VIEW)
    2577           0 :             continue;
    2578             : 
    2579             :         /* Don't bother computing anything for non-target tables, either */
    2580           0 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2581           0 :             continue;
    2582             : 
    2583           0 :         numParents = tbinfo->numParents;
    2584           0 :         parents = tbinfo->parents;
    2585             : 
    2586           0 :         if (numParents == 0)
    2587           0 :             continue;           /* nothing to see here, move along */
    2588             : 
    2589             :         /* scan for inherited CHECK constraints */
    2590           0 :         for (j = 0; j < tbinfo->ncheck; j++)
    2591             :         {
    2592             :             ConstraintInfo *constr;
    2593             : 
    2594           0 :             constr = &(tbinfo->checkexprs[j]);
    2595             : 
    2596           0 :             for (k = 0; k < numParents; k++)
    2597             :             {
    2598             :                 int         l;
    2599             : 
    2600           0 :                 parent = parents[k];
    2601           0 :                 for (l = 0; l < parent->ncheck; l++)
    2602             :                 {
    2603           0 :                     ConstraintInfo *pconstr = &(parent->checkexprs[l]);
    2604             : 
    2605           0 :                     if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
    2606             :                     {
    2607           0 :                         constr->conislocal = false;
    2608           0 :                         break;
    2609             :                     }
    2610             :                 }
    2611           0 :                 if (!constr->conislocal)
    2612           0 :                     break;
    2613             :             }
    2614             :         }
    2615             :     }
    2616           0 : }
    2617             : 
    2618             : 
    2619             : /*
    2620             :  * dumpDatabase:
    2621             :  *  dump the database definition
    2622             :  */
    2623             : static void
    2624          68 : dumpDatabase(Archive *fout)
    2625             : {
    2626          68 :     DumpOptions *dopt = fout->dopt;
    2627          68 :     PQExpBuffer dbQry = createPQExpBuffer();
    2628          68 :     PQExpBuffer delQry = createPQExpBuffer();
    2629          68 :     PQExpBuffer creaQry = createPQExpBuffer();
    2630          68 :     PQExpBuffer labelq = createPQExpBuffer();
    2631          68 :     PGconn     *conn = GetConnection(fout);
    2632             :     PGresult   *res;
    2633             :     int         i_tableoid,
    2634             :                 i_oid,
    2635             :                 i_datname,
    2636             :                 i_dba,
    2637             :                 i_encoding,
    2638             :                 i_collate,
    2639             :                 i_ctype,
    2640             :                 i_frozenxid,
    2641             :                 i_minmxid,
    2642             :                 i_datacl,
    2643             :                 i_rdatacl,
    2644             :                 i_datistemplate,
    2645             :                 i_datconnlimit,
    2646             :                 i_tablespace;
    2647             :     CatalogId   dbCatId;
    2648             :     DumpId      dbDumpId;
    2649             :     const char *datname,
    2650             :                *dba,
    2651             :                *encoding,
    2652             :                *collate,
    2653             :                *ctype,
    2654             :                *datacl,
    2655             :                *rdatacl,
    2656             :                *datistemplate,
    2657             :                *datconnlimit,
    2658             :                *tablespace;
    2659             :     uint32      frozenxid,
    2660             :                 minmxid;
    2661             :     char       *qdatname;
    2662             : 
    2663          68 :     pg_log_info("saving database definition");
    2664             : 
    2665             :     /*
    2666             :      * Fetch the database-level properties for this database.
    2667             :      *
    2668             :      * The order in which privileges are in the ACL string (the order they
    2669             :      * have been GRANT'd in, which the backend maintains) must be preserved to
    2670             :      * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
    2671             :      * those are dumped in the correct order.  Note that initial privileges
    2672             :      * (pg_init_privs) are not supported on databases, so this logic cannot
    2673             :      * make use of buildACLQueries().
    2674             :      */
    2675          68 :     if (fout->remoteVersion >= 90600)
    2676             :     {
    2677          68 :         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
    2678             :                           "(%s datdba) AS dba, "
    2679             :                           "pg_encoding_to_char(encoding) AS encoding, "
    2680             :                           "datcollate, datctype, datfrozenxid, datminmxid, "
    2681             :                           "(SELECT array_agg(acl ORDER BY row_n) FROM "
    2682             :                           "  (SELECT acl, row_n FROM "
    2683             :                           "     unnest(coalesce(datacl,acldefault('d',datdba))) "
    2684             :                           "     WITH ORDINALITY AS perm(acl,row_n) "
    2685             :                           "   WHERE NOT EXISTS ( "
    2686             :                           "     SELECT 1 "
    2687             :                           "     FROM unnest(acldefault('d',datdba)) "
    2688             :                           "       AS init(init_acl) "
    2689             :                           "     WHERE acl = init_acl)) AS datacls) "
    2690             :                           " AS datacl, "
    2691             :                           "(SELECT array_agg(acl ORDER BY row_n) FROM "
    2692             :                           "  (SELECT acl, row_n FROM "
    2693             :                           "     unnest(acldefault('d',datdba)) "
    2694             :                           "     WITH ORDINALITY AS initp(acl,row_n) "
    2695             :                           "   WHERE NOT EXISTS ( "
    2696             :                           "     SELECT 1 "
    2697             :                           "     FROM unnest(coalesce(datacl,acldefault('d',datdba))) "
    2698             :                           "       AS permp(orig_acl) "
    2699             :                           "     WHERE acl = orig_acl)) AS rdatacls) "
    2700             :                           " AS rdatacl, "
    2701             :                           "datistemplate, datconnlimit, "
    2702             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    2703             :                           "shobj_description(oid, 'pg_database') AS description "
    2704             : 
    2705             :                           "FROM pg_database "
    2706             :                           "WHERE datname = current_database()",
    2707             :                           username_subquery);
    2708             :     }
    2709           0 :     else if (fout->remoteVersion >= 90300)
    2710             :     {
    2711           0 :         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
    2712             :                           "(%s datdba) AS dba, "
    2713             :                           "pg_encoding_to_char(encoding) AS encoding, "
    2714             :                           "datcollate, datctype, datfrozenxid, datminmxid, "
    2715             :                           "datacl, '' as rdatacl, datistemplate, datconnlimit, "
    2716             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    2717             :                           "shobj_description(oid, 'pg_database') AS description "
    2718             : 
    2719             :                           "FROM pg_database "
    2720             :                           "WHERE datname = current_database()",
    2721             :                           username_subquery);
    2722             :     }
    2723           0 :     else if (fout->remoteVersion >= 80400)
    2724             :     {
    2725           0 :         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
    2726             :                           "(%s datdba) AS dba, "
    2727             :                           "pg_encoding_to_char(encoding) AS encoding, "
    2728             :                           "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
    2729             :                           "datacl, '' as rdatacl, datistemplate, datconnlimit, "
    2730             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    2731             :                           "shobj_description(oid, 'pg_database') AS description "
    2732             : 
    2733             :                           "FROM pg_database "
    2734             :                           "WHERE datname = current_database()",
    2735             :                           username_subquery);
    2736             :     }
    2737           0 :     else if (fout->remoteVersion >= 80200)
    2738             :     {
    2739           0 :         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
    2740             :                           "(%s datdba) AS dba, "
    2741             :                           "pg_encoding_to_char(encoding) AS encoding, "
    2742             :                           "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
    2743             :                           "datacl, '' as rdatacl, datistemplate, datconnlimit, "
    2744             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    2745             :                           "shobj_description(oid, 'pg_database') AS description "
    2746             : 
    2747             :                           "FROM pg_database "
    2748             :                           "WHERE datname = current_database()",
    2749             :                           username_subquery);
    2750             :     }
    2751             :     else
    2752             :     {
    2753           0 :         appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
    2754             :                           "(%s datdba) AS dba, "
    2755             :                           "pg_encoding_to_char(encoding) AS encoding, "
    2756             :                           "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
    2757             :                           "datacl, '' as rdatacl, datistemplate, "
    2758             :                           "-1 as datconnlimit, "
    2759             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
    2760             :                           "FROM pg_database "
    2761             :                           "WHERE datname = current_database()",
    2762             :                           username_subquery);
    2763             :     }
    2764             : 
    2765          68 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    2766             : 
    2767          68 :     i_tableoid = PQfnumber(res, "tableoid");
    2768          68 :     i_oid = PQfnumber(res, "oid");
    2769          68 :     i_datname = PQfnumber(res, "datname");
    2770          68 :     i_dba = PQfnumber(res, "dba");
    2771          68 :     i_encoding = PQfnumber(res, "encoding");
    2772          68 :     i_collate = PQfnumber(res, "datcollate");
    2773          68 :     i_ctype = PQfnumber(res, "datctype");
    2774          68 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    2775          68 :     i_minmxid = PQfnumber(res, "datminmxid");
    2776          68 :     i_datacl = PQfnumber(res, "datacl");
    2777          68 :     i_rdatacl = PQfnumber(res, "rdatacl");
    2778          68 :     i_datistemplate = PQfnumber(res, "datistemplate");
    2779          68 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    2780          68 :     i_tablespace = PQfnumber(res, "tablespace");
    2781             : 
    2782          68 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    2783          68 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    2784          68 :     datname = PQgetvalue(res, 0, i_datname);
    2785          68 :     dba = PQgetvalue(res, 0, i_dba);
    2786          68 :     encoding = PQgetvalue(res, 0, i_encoding);
    2787          68 :     collate = PQgetvalue(res, 0, i_collate);
    2788          68 :     ctype = PQgetvalue(res, 0, i_ctype);
    2789          68 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    2790          68 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    2791          68 :     datacl = PQgetvalue(res, 0, i_datacl);
    2792          68 :     rdatacl = PQgetvalue(res, 0, i_rdatacl);
    2793          68 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    2794          68 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    2795          68 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    2796             : 
    2797          68 :     qdatname = pg_strdup(fmtId(datname));
    2798             : 
    2799             :     /*
    2800             :      * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
    2801             :      * and tablespace since those can't be altered later.  Other DB properties
    2802             :      * are left to the DATABASE PROPERTIES entry, so that they can be applied
    2803             :      * after reconnecting to the target DB.
    2804             :      */
    2805          68 :     appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    2806             :                       qdatname);
    2807          68 :     if (strlen(encoding) > 0)
    2808             :     {
    2809          68 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    2810          68 :         appendStringLiteralAH(creaQry, encoding, fout);
    2811             :     }
    2812          68 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    2813             :     {
    2814          68 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    2815          68 :         appendStringLiteralAH(creaQry, collate, fout);
    2816             :     }
    2817             :     else
    2818             :     {
    2819           0 :         if (strlen(collate) > 0)
    2820             :         {
    2821           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    2822           0 :             appendStringLiteralAH(creaQry, collate, fout);
    2823             :         }
    2824           0 :         if (strlen(ctype) > 0)
    2825             :         {
    2826           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    2827           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    2828             :         }
    2829             :     }
    2830             : 
    2831             :     /*
    2832             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    2833             :      * thing; the decision whether to specify a tablespace should be left till
    2834             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    2835             :      * label the DATABASE entry with the tablespace and let the normal
    2836             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    2837             :      * attention to default_tablespace, so that won't work.
    2838             :      */
    2839          68 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    2840           0 :         !dopt->outputNoTablespaces)
    2841           0 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    2842             :                           fmtId(tablespace));
    2843          68 :     appendPQExpBufferStr(creaQry, ";\n");
    2844             : 
    2845          68 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    2846             :                       qdatname);
    2847             : 
    2848          68 :     dbDumpId = createDumpId();
    2849             : 
    2850          68 :     ArchiveEntry(fout,
    2851             :                  dbCatId,       /* catalog ID */
    2852             :                  dbDumpId,      /* dump ID */
    2853          68 :                  ARCHIVE_OPTS(.tag = datname,
    2854             :                               .owner = dba,
    2855             :                               .description = "DATABASE",
    2856             :                               .section = SECTION_PRE_DATA,
    2857             :                               .createStmt = creaQry->data,
    2858             :                               .dropStmt = delQry->data));
    2859             : 
    2860             :     /* Compute correct tag for archive entry */
    2861          68 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    2862             : 
    2863             :     /* Dump DB comment if any */
    2864          68 :     if (fout->remoteVersion >= 80200)
    2865             :     {
    2866             :         /*
    2867             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    2868             :          * cannot use the dumpComment() code used for other database objects.
    2869             :          * Be careful that the ArchiveEntry parameters match that function.
    2870             :          */
    2871          68 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    2872             : 
    2873          68 :         if (comment && *comment && !dopt->no_comments)
    2874             :         {
    2875          28 :             resetPQExpBuffer(dbQry);
    2876             : 
    2877             :             /*
    2878             :              * Generates warning when loaded into a differently-named
    2879             :              * database.
    2880             :              */
    2881          28 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    2882          28 :             appendStringLiteralAH(dbQry, comment, fout);
    2883          28 :             appendPQExpBufferStr(dbQry, ";\n");
    2884             : 
    2885          28 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    2886          28 :                          ARCHIVE_OPTS(.tag = labelq->data,
    2887             :                                       .owner = dba,
    2888             :                                       .description = "COMMENT",
    2889             :                                       .section = SECTION_NONE,
    2890             :                                       .createStmt = dbQry->data,
    2891             :                                       .deps = &dbDumpId,
    2892             :                                       .nDeps = 1));
    2893             :         }
    2894             :     }
    2895             :     else
    2896             :     {
    2897           0 :         dumpComment(fout, "DATABASE", qdatname, NULL, dba,
    2898             :                     dbCatId, 0, dbDumpId);
    2899             :     }
    2900             : 
    2901             :     /* Dump DB security label, if enabled */
    2902          68 :     if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
    2903             :     {
    2904             :         PGresult   *shres;
    2905             :         PQExpBuffer seclabelQry;
    2906             : 
    2907          68 :         seclabelQry = createPQExpBuffer();
    2908             : 
    2909          68 :         buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
    2910          68 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    2911          68 :         resetPQExpBuffer(seclabelQry);
    2912          68 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    2913          68 :         if (seclabelQry->len > 0)
    2914           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    2915           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    2916             :                                       .owner = dba,
    2917             :                                       .description = "SECURITY LABEL",
    2918             :                                       .section = SECTION_NONE,
    2919             :                                       .createStmt = seclabelQry->data,
    2920             :                                       .deps = &dbDumpId,
    2921             :                                       .nDeps = 1));
    2922          68 :         destroyPQExpBuffer(seclabelQry);
    2923          68 :         PQclear(shres);
    2924             :     }
    2925             : 
    2926             :     /*
    2927             :      * Dump ACL if any.  Note that we do not support initial privileges
    2928             :      * (pg_init_privs) on databases.
    2929             :      */
    2930          68 :     dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
    2931             :             qdatname, NULL, NULL,
    2932             :             dba, datacl, rdatacl, "", "");
    2933             : 
    2934             :     /*
    2935             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    2936             :      * non-default database-level properties.  (The reason this must be
    2937             :      * separate is that we cannot put any additional commands into the TOC
    2938             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    2939             :      * in an implicit transaction block, and the backend won't allow CREATE
    2940             :      * DATABASE in that context.)
    2941             :      */
    2942          68 :     resetPQExpBuffer(creaQry);
    2943          68 :     resetPQExpBuffer(delQry);
    2944             : 
    2945          68 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    2946           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    2947             :                           qdatname, datconnlimit);
    2948             : 
    2949          68 :     if (strcmp(datistemplate, "t") == 0)
    2950             :     {
    2951           2 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    2952             :                           qdatname);
    2953             : 
    2954             :         /*
    2955             :          * The backend won't accept DROP DATABASE on a template database.  We
    2956             :          * can deal with that by removing the template marking before the DROP
    2957             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    2958             :          * since no such command is currently supported, fake it with a direct
    2959             :          * UPDATE on pg_database.
    2960             :          */
    2961           2 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    2962             :                              "SET datistemplate = false WHERE datname = ");
    2963           2 :         appendStringLiteralAH(delQry, datname, fout);
    2964           2 :         appendPQExpBufferStr(delQry, ";\n");
    2965             :     }
    2966             : 
    2967             :     /* Add database-specific SET options */
    2968          68 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    2969             : 
    2970             :     /*
    2971             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    2972             :      * entry, too, for lack of a better place.
    2973             :      */
    2974          68 :     if (dopt->binary_upgrade)
    2975             :     {
    2976          14 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    2977          14 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    2978             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    2979             :                           "WHERE datname = ",
    2980             :                           frozenxid, minmxid);
    2981          14 :         appendStringLiteralAH(creaQry, datname, fout);
    2982          14 :         appendPQExpBufferStr(creaQry, ";\n");
    2983             :     }
    2984             : 
    2985          68 :     if (creaQry->len > 0)
    2986          18 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    2987          18 :                      ARCHIVE_OPTS(.tag = datname,
    2988             :                                   .owner = dba,
    2989             :                                   .description = "DATABASE PROPERTIES",
    2990             :                                   .section = SECTION_PRE_DATA,
    2991             :                                   .createStmt = creaQry->data,
    2992             :                                   .dropStmt = delQry->data,
    2993             :                                   .deps = &dbDumpId));
    2994             : 
    2995             :     /*
    2996             :      * pg_largeobject comes from the old system intact, so set its
    2997             :      * relfrozenxids and relminmxids.
    2998             :      */
    2999          68 :     if (dopt->binary_upgrade)
    3000             :     {
    3001             :         PGresult   *lo_res;
    3002          14 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3003          14 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3004             :         int         i_relfrozenxid,
    3005             :                     i_relminmxid;
    3006             : 
    3007             :         /*
    3008             :          * pg_largeobject
    3009             :          */
    3010          14 :         if (fout->remoteVersion >= 90300)
    3011          14 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
    3012             :                               "FROM pg_catalog.pg_class\n"
    3013             :                               "WHERE oid = %u;\n",
    3014             :                               LargeObjectRelationId);
    3015             :         else
    3016           0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
    3017             :                               "FROM pg_catalog.pg_class\n"
    3018             :                               "WHERE oid = %u;\n",
    3019             :                               LargeObjectRelationId);
    3020             : 
    3021          14 :         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
    3022             : 
    3023          14 :         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3024          14 :         i_relminmxid = PQfnumber(lo_res, "relminmxid");
    3025             : 
    3026          14 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3027          28 :         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
    3028             :                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3029             :                           "WHERE oid = %u;\n",
    3030          14 :                           atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
    3031          14 :                           atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
    3032             :                           LargeObjectRelationId);
    3033          14 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3034          14 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3035             :                                   .description = "pg_largeobject",
    3036             :                                   .section = SECTION_PRE_DATA,
    3037             :                                   .createStmt = loOutQry->data));
    3038             : 
    3039          14 :         PQclear(lo_res);
    3040             : 
    3041          14 :         destroyPQExpBuffer(loFrozenQry);
    3042          14 :         destroyPQExpBuffer(loOutQry);
    3043             :     }
    3044             : 
    3045          68 :     PQclear(res);
    3046             : 
    3047          68 :     free(qdatname);
    3048          68 :     destroyPQExpBuffer(dbQry);
    3049          68 :     destroyPQExpBuffer(delQry);
    3050          68 :     destroyPQExpBuffer(creaQry);
    3051          68 :     destroyPQExpBuffer(labelq);
    3052          68 : }
    3053             : 
    3054             : /*
    3055             :  * Collect any database-specific or role-and-database-specific SET options
    3056             :  * for this database, and append them to outbuf.
    3057             :  */
    3058             : static void
    3059          68 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3060             :                    const char *dbname, Oid dboid)
    3061             : {
    3062          68 :     PGconn     *conn = GetConnection(AH);
    3063          68 :     PQExpBuffer buf = createPQExpBuffer();
    3064             :     PGresult   *res;
    3065          68 :     int         count = 1;
    3066             : 
    3067             :     /*
    3068             :      * First collect database-specific options.  Pre-8.4 server versions lack
    3069             :      * unnest(), so we do this the hard way by querying once per subscript.
    3070             :      */
    3071             :     for (;;)
    3072             :     {
    3073         140 :         if (AH->remoteVersion >= 90000)
    3074         104 :             printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
    3075             :                               "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3076             :                               count, dboid);
    3077             :         else
    3078           0 :             printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
    3079             : 
    3080         104 :         res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3081             : 
    3082         146 :         if (PQntuples(res) == 1 &&
    3083          42 :             !PQgetisnull(res, 0, 0))
    3084             :         {
    3085          36 :             makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
    3086             :                                    "DATABASE", dbname, NULL, NULL,
    3087             :                                    outbuf);
    3088          36 :             PQclear(res);
    3089          36 :             count++;
    3090             :         }
    3091             :         else
    3092             :         {
    3093          68 :             PQclear(res);
    3094          68 :             break;
    3095             :         }
    3096             :     }
    3097             : 
    3098             :     /* Now look for role-and-database-specific options */
    3099          68 :     if (AH->remoteVersion >= 90000)
    3100             :     {
    3101             :         /* Here we can assume we have unnest() */
    3102          68 :         printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3103             :                           "FROM pg_db_role_setting s, pg_roles r "
    3104             :                           "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3105             :                           dboid);
    3106             : 
    3107          68 :         res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3108             : 
    3109          68 :         if (PQntuples(res) > 0)
    3110             :         {
    3111             :             int         i;
    3112             : 
    3113           0 :             for (i = 0; i < PQntuples(res); i++)
    3114           0 :                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3115           0 :                                        "ROLE", PQgetvalue(res, i, 0),
    3116             :                                        "DATABASE", dbname,
    3117             :                                        outbuf);
    3118             :         }
    3119             : 
    3120          68 :         PQclear(res);
    3121             :     }
    3122             : 
    3123          68 :     destroyPQExpBuffer(buf);
    3124          68 : }
    3125             : 
    3126             : /*
    3127             :  * dumpEncoding: put the correct encoding into the archive
    3128             :  */
    3129             : static void
    3130         156 : dumpEncoding(Archive *AH)
    3131             : {
    3132         156 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3133         156 :     PQExpBuffer qry = createPQExpBuffer();
    3134             : 
    3135         156 :     pg_log_info("saving encoding = %s", encname);
    3136             : 
    3137         156 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3138         156 :     appendStringLiteralAH(qry, encname, AH);
    3139         156 :     appendPQExpBufferStr(qry, ";\n");
    3140             : 
    3141         156 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3142         156 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3143             :                               .description = "ENCODING",
    3144             :                               .section = SECTION_PRE_DATA,
    3145             :                               .createStmt = qry->data));
    3146             : 
    3147         156 :     destroyPQExpBuffer(qry);
    3148         156 : }
    3149             : 
    3150             : 
    3151             : /*
    3152             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3153             :  */
    3154             : static void
    3155         156 : dumpStdStrings(Archive *AH)
    3156             : {
    3157         156 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3158         156 :     PQExpBuffer qry = createPQExpBuffer();
    3159             : 
    3160         156 :     pg_log_info("saving standard_conforming_strings = %s",
    3161             :                 stdstrings);
    3162             : 
    3163         156 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3164             :                       stdstrings);
    3165             : 
    3166         156 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3167         156 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3168             :                               .description = "STDSTRINGS",
    3169             :                               .section = SECTION_PRE_DATA,
    3170             :                               .createStmt = qry->data));
    3171             : 
    3172         156 :     destroyPQExpBuffer(qry);
    3173         156 : }
    3174             : 
    3175             : /*
    3176             :  * dumpSearchPath: record the active search_path in the archive
    3177             :  */
    3178             : static void
    3179         156 : dumpSearchPath(Archive *AH)
    3180             : {
    3181         156 :     PQExpBuffer qry = createPQExpBuffer();
    3182         156 :     PQExpBuffer path = createPQExpBuffer();
    3183             :     PGresult   *res;
    3184         156 :     char      **schemanames = NULL;
    3185         156 :     int         nschemanames = 0;
    3186             :     int         i;
    3187             : 
    3188             :     /*
    3189             :      * We use the result of current_schemas(), not the search_path GUC,
    3190             :      * because that might contain wildcards such as "$user", which won't
    3191             :      * necessarily have the same value during restore.  Also, this way avoids
    3192             :      * listing schemas that may appear in search_path but not actually exist,
    3193             :      * which seems like a prudent exclusion.
    3194             :      */
    3195         156 :     res = ExecuteSqlQueryForSingleRow(AH,
    3196             :                                       "SELECT pg_catalog.current_schemas(false)");
    3197             : 
    3198         156 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3199           0 :         fatal("could not parse result of current_schemas()");
    3200             : 
    3201             :     /*
    3202             :      * We use set_config(), not a simple "SET search_path" command, because
    3203             :      * the latter has less-clean behavior if the search path is empty.  While
    3204             :      * that's likely to get fixed at some point, it seems like a good idea to
    3205             :      * be as backwards-compatible as possible in what we put into archives.
    3206             :      */
    3207         156 :     for (i = 0; i < nschemanames; i++)
    3208             :     {
    3209           0 :         if (i > 0)
    3210           0 :             appendPQExpBufferStr(path, ", ");
    3211           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3212             :     }
    3213             : 
    3214         156 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3215         156 :     appendStringLiteralAH(qry, path->data, AH);
    3216         156 :     appendPQExpBufferStr(qry, ", false);\n");
    3217             : 
    3218         156 :     pg_log_info("saving search_path = %s", path->data);
    3219             : 
    3220         156 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3221         156 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3222             :                               .description = "SEARCHPATH",
    3223             :                               .section = SECTION_PRE_DATA,
    3224             :                               .createStmt = qry->data));
    3225             : 
    3226             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3227         156 :     AH->searchpath = pg_strdup(qry->data);
    3228             : 
    3229         156 :     if (schemanames)
    3230         156 :         free(schemanames);
    3231         156 :     PQclear(res);
    3232         156 :     destroyPQExpBuffer(qry);
    3233         156 :     destroyPQExpBuffer(path);
    3234         156 : }
    3235             : 
    3236             : 
    3237             : /*
    3238             :  * getBlobs:
    3239             :  *  Collect schema-level data about large objects
    3240             :  */
    3241             : static void
    3242         140 : getBlobs(Archive *fout)
    3243             : {
    3244         140 :     DumpOptions *dopt = fout->dopt;
    3245         140 :     PQExpBuffer blobQry = createPQExpBuffer();
    3246             :     BlobInfo   *binfo;
    3247             :     DumpableObject *bdata;
    3248             :     PGresult   *res;
    3249             :     int         ntups;
    3250             :     int         i;
    3251             :     int         i_oid;
    3252             :     int         i_lomowner;
    3253             :     int         i_lomacl;
    3254             :     int         i_rlomacl;
    3255             :     int         i_initlomacl;
    3256             :     int         i_initrlomacl;
    3257             : 
    3258         140 :     pg_log_info("reading large objects");
    3259             : 
    3260             :     /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
    3261         140 :     if (fout->remoteVersion >= 90600)
    3262             :     {
    3263         140 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    3264         140 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    3265         140 :         PQExpBuffer init_acl_subquery = createPQExpBuffer();
    3266         140 :         PQExpBuffer init_racl_subquery = createPQExpBuffer();
    3267             : 
    3268         140 :         buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
    3269             :                         init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
    3270         140 :                         dopt->binary_upgrade);
    3271             : 
    3272         140 :         appendPQExpBuffer(blobQry,
    3273             :                           "SELECT l.oid, (%s l.lomowner) AS rolname, "
    3274             :                           "%s AS lomacl, "
    3275             :                           "%s AS rlomacl, "
    3276             :                           "%s AS initlomacl, "
    3277             :                           "%s AS initrlomacl "
    3278             :                           "FROM pg_largeobject_metadata l "
    3279             :                           "LEFT JOIN pg_init_privs pip ON "
    3280             :                           "(l.oid = pip.objoid "
    3281             :                           "AND pip.classoid = 'pg_largeobject'::regclass "
    3282             :                           "AND pip.objsubid = 0) ",
    3283             :                           username_subquery,
    3284             :                           acl_subquery->data,
    3285             :                           racl_subquery->data,
    3286             :                           init_acl_subquery->data,
    3287             :                           init_racl_subquery->data);
    3288             : 
    3289         140 :         destroyPQExpBuffer(acl_subquery);
    3290         140 :         destroyPQExpBuffer(racl_subquery);
    3291         140 :         destroyPQExpBuffer(init_acl_subquery);
    3292         140 :         destroyPQExpBuffer(init_racl_subquery);
    3293             :     }
    3294           0 :     else if (fout->remoteVersion >= 90000)
    3295           0 :         appendPQExpBuffer(blobQry,
    3296             :                           "SELECT oid, (%s lomowner) AS rolname, lomacl, "
    3297             :                           "NULL AS rlomacl, NULL AS initlomacl, "
    3298             :                           "NULL AS initrlomacl "
    3299             :                           " FROM pg_largeobject_metadata",
    3300             :                           username_subquery);
    3301             :     else
    3302           0 :         appendPQExpBufferStr(blobQry,
    3303             :                              "SELECT DISTINCT loid AS oid, "
    3304             :                              "NULL::name AS rolname, NULL::oid AS lomacl, "
    3305             :                              "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
    3306             :                              "NULL::oid AS initrlomacl "
    3307             :                              " FROM pg_largeobject");
    3308             : 
    3309         140 :     res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
    3310             : 
    3311         140 :     i_oid = PQfnumber(res, "oid");
    3312         140 :     i_lomowner = PQfnumber(res, "rolname");
    3313         140 :     i_lomacl = PQfnumber(res, "lomacl");
    3314         140 :     i_rlomacl = PQfnumber(res, "rlomacl");
    3315         140 :     i_initlomacl = PQfnumber(res, "initlomacl");
    3316         140 :     i_initrlomacl = PQfnumber(res, "initrlomacl");
    3317             : 
    3318         140 :     ntups = PQntuples(res);
    3319             : 
    3320             :     /*
    3321             :      * Each large object has its own BLOB archive entry.
    3322             :      */
    3323         140 :     binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
    3324             : 
    3325         202 :     for (i = 0; i < ntups; i++)
    3326             :     {
    3327          62 :         binfo[i].dobj.objType = DO_BLOB;
    3328          62 :         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
    3329          62 :         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    3330          62 :         AssignDumpId(&binfo[i].dobj);
    3331             : 
    3332          62 :         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
    3333          62 :         binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
    3334          62 :         binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
    3335          62 :         binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
    3336          62 :         binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
    3337          62 :         binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
    3338             : 
    3339          80 :         if (PQgetisnull(res, i, i_lomacl) &&
    3340          36 :             PQgetisnull(res, i, i_rlomacl) &&
    3341          36 :             PQgetisnull(res, i, i_initlomacl) &&
    3342          18 :             PQgetisnull(res, i, i_initrlomacl))
    3343          18 :             binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    3344             : 
    3345             :         /*
    3346             :          * In binary-upgrade mode for blobs, we do *not* dump out the blob
    3347             :          * data, as it will be copied by pg_upgrade, which simply copies the
    3348             :          * pg_largeobject table. We *do* however dump out anything but the
    3349             :          * data, as pg_upgrade copies just pg_largeobject, but not
    3350             :          * pg_largeobject_metadata, after the dump is restored.
    3351             :          */
    3352          62 :         if (dopt->binary_upgrade)
    3353           8 :             binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
    3354             :     }
    3355             : 
    3356             :     /*
    3357             :      * If we have any large objects, a "BLOBS" archive entry is needed. This
    3358             :      * is just a placeholder for sorting; it carries no data now.
    3359             :      */
    3360         140 :     if (ntups > 0)
    3361             :     {
    3362          50 :         bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    3363          50 :         bdata->objType = DO_BLOB_DATA;
    3364          50 :         bdata->catId = nilCatalogId;
    3365          50 :         AssignDumpId(bdata);
    3366          50 :         bdata->name = pg_strdup("BLOBS");
    3367             :     }
    3368             : 
    3369         140 :     PQclear(res);
    3370         140 :     destroyPQExpBuffer(blobQry);
    3371         140 : }
    3372             : 
    3373             : /*
    3374             :  * dumpBlob
    3375             :  *
    3376             :  * dump the definition (metadata) of the given large object
    3377             :  */
    3378             : static void
    3379          62 : dumpBlob(Archive *fout, BlobInfo *binfo)
    3380             : {
    3381          62 :     PQExpBuffer cquery = createPQExpBuffer();
    3382          62 :     PQExpBuffer dquery = createPQExpBuffer();
    3383             : 
    3384          62 :     appendPQExpBuffer(cquery,
    3385             :                       "SELECT pg_catalog.lo_create('%s');\n",
    3386             :                       binfo->dobj.name);
    3387             : 
    3388          62 :     appendPQExpBuffer(dquery,
    3389             :                       "SELECT pg_catalog.lo_unlink('%s');\n",
    3390             :                       binfo->dobj.name);
    3391             : 
    3392          62 :     if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    3393          62 :         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
    3394          62 :                      ARCHIVE_OPTS(.tag = binfo->dobj.name,
    3395             :                                   .owner = binfo->rolname,
    3396             :                                   .description = "BLOB",
    3397             :                                   .section = SECTION_PRE_DATA,
    3398             :                                   .createStmt = cquery->data,
    3399             :                                   .dropStmt = dquery->data));
    3400             : 
    3401             :     /* Dump comment if any */
    3402          62 :     if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    3403         124 :         dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
    3404          62 :                     NULL, binfo->rolname,
    3405             :                     binfo->dobj.catId, 0, binfo->dobj.dumpId);
    3406             : 
    3407             :     /* Dump security label if any */
    3408          62 :     if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    3409         124 :         dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
    3410          62 :                      NULL, binfo->rolname,
    3411             :                      binfo->dobj.catId, 0, binfo->dobj.dumpId);
    3412             : 
    3413             :     /* Dump ACL if any */
    3414          62 :     if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
    3415          44 :         dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
    3416          44 :                 binfo->dobj.name, NULL,
    3417          44 :                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
    3418          44 :                 binfo->initblobacl, binfo->initrblobacl);
    3419             : 
    3420          62 :     destroyPQExpBuffer(cquery);
    3421          62 :     destroyPQExpBuffer(dquery);
    3422          62 : }
    3423             : 
    3424             : /*
    3425             :  * dumpBlobs:
    3426             :  *  dump the data contents of all large objects
    3427             :  */
    3428             : static int
    3429          42 : dumpBlobs(Archive *fout, void *arg)
    3430             : {
    3431             :     const char *blobQry;
    3432             :     const char *blobFetchQry;
    3433          42 :     PGconn     *conn = GetConnection(fout);
    3434             :     PGresult   *res;
    3435             :     char        buf[LOBBUFSIZE];
    3436             :     int         ntups;
    3437             :     int         i;
    3438             :     int         cnt;
    3439             : 
    3440          42 :     pg_log_info("saving large objects");
    3441             : 
    3442             :     /*
    3443             :      * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
    3444             :      * the already-in-memory dumpable objects instead...
    3445             :      */
    3446          42 :     if (fout->remoteVersion >= 90000)
    3447          42 :         blobQry =
    3448             :             "DECLARE bloboid CURSOR FOR "
    3449             :             "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
    3450             :     else
    3451           0 :         blobQry =
    3452             :             "DECLARE bloboid CURSOR FOR "
    3453             :             "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
    3454             : 
    3455          42 :     ExecuteSqlStatement(fout, blobQry);
    3456             : 
    3457             :     /* Command to fetch from cursor */
    3458          42 :     blobFetchQry = "FETCH 1000 IN bloboid";
    3459             : 
    3460             :     do
    3461             :     {
    3462             :         /* Do a fetch */
    3463          84 :         res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
    3464             : 
    3465             :         /* Process the tuples, if any */
    3466          84 :         ntups = PQntuples(res);
    3467         134 :         for (i = 0; i < ntups; i++)
    3468             :         {
    3469             :             Oid         blobOid;
    3470             :             int         loFd;
    3471             : 
    3472          50 :             blobOid = atooid(PQgetvalue(res, i, 0));
    3473             :             /* Open the BLOB */
    3474          50 :             loFd = lo_open(conn, blobOid, INV_READ);
    3475          50 :             if (loFd == -1)
    3476           0 :                 fatal("could not open large object %u: %s",
    3477             :                       blobOid, PQerrorMessage(conn));
    3478             : 
    3479          50 :             StartBlob(fout, blobOid);
    3480             : 
    3481             :             /* Now read it in chunks, sending data to archive */
    3482             :             do
    3483             :             {
    3484          96 :                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    3485          96 :                 if (cnt < 0)
    3486           0 :                     fatal("error reading large object %u: %s",
    3487             :                           blobOid, PQerrorMessage(conn));
    3488             : 
    3489          96 :                 WriteData(fout, buf, cnt);
    3490          96 :             } while (cnt > 0);
    3491             : 
    3492          50 :             lo_close(conn, loFd);
    3493             : 
    3494          50 :             EndBlob(fout, blobOid);
    3495             :         }
    3496             : 
    3497          84 :         PQclear(res);
    3498          84 :     } while (ntups > 0);
    3499             : 
    3500          42 :     return 1;
    3501             : }
    3502             : 
    3503             : /*
    3504             :  * getPolicies
    3505             :  *    get information about policies on a dumpable table.
    3506             :  */
    3507             : void
    3508         156 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    3509             : {
    3510             :     PQExpBuffer query;
    3511             :     PGresult   *res;
    3512             :     PolicyInfo *polinfo;
    3513             :     int         i_oid;
    3514             :     int         i_tableoid;
    3515             :     int         i_polname;
    3516             :     int         i_polcmd;
    3517             :     int         i_polpermissive;
    3518             :     int         i_polroles;
    3519             :     int         i_polqual;
    3520             :     int         i_polwithcheck;
    3521             :     int         i,
    3522             :                 j,
    3523             :                 ntups;
    3524             : 
    3525         156 :     if (fout->remoteVersion < 90500)
    3526           0 :         return;
    3527             : 
    3528         156 :     query = createPQExpBuffer();
    3529             : 
    3530       35736 :     for (i = 0; i < numTables; i++)
    3531             :     {
    3532       35580 :         TableInfo  *tbinfo = &tblinfo[i];
    3533             : 
    3534             :         /* Ignore row security on tables not to be dumped */
    3535       35580 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    3536       30262 :             continue;
    3537             : 
    3538        5318 :         pg_log_info("reading row security enabled for table \"%s.%s\"",
    3539             :                     tbinfo->dobj.namespace->dobj.name,
    3540             :                     tbinfo->dobj.name);
    3541             : 
    3542             :         /*
    3543             :          * Get row security enabled information for the table. We represent
    3544             :          * RLS being enabled on a table by creating a PolicyInfo object with
    3545             :          * null polname.
    3546             :          */
    3547        5318 :         if (tbinfo->rowsec)
    3548             :         {
    3549             :             /*
    3550             :              * Note: use tableoid 0 so that this object won't be mistaken for
    3551             :              * something that pg_depend entries apply to.
    3552             :              */
    3553          68 :             polinfo = pg_malloc(sizeof(PolicyInfo));
    3554          68 :             polinfo->dobj.objType = DO_POLICY;
    3555          68 :             polinfo->dobj.catId.tableoid = 0;
    3556          68 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3557          68 :             AssignDumpId(&polinfo->dobj);
    3558          68 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    3559          68 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    3560          68 :             polinfo->poltable = tbinfo;
    3561          68 :             polinfo->polname = NULL;
    3562          68 :             polinfo->polcmd = '\0';
    3563          68 :             polinfo->polpermissive = 0;
    3564          68 :             polinfo->polroles = NULL;
    3565          68 :             polinfo->polqual = NULL;
    3566          68 :             polinfo->polwithcheck = NULL;
    3567             :         }
    3568             : 
    3569        5318 :         pg_log_info("reading policies for table \"%s.%s\"",
    3570             :                     tbinfo->dobj.namespace->dobj.name,
    3571             :                     tbinfo->dobj.name);
    3572             : 
    3573        5318 :         resetPQExpBuffer(query);
    3574             : 
    3575             :         /* Get the policies for the table. */
    3576        5318 :         if (fout->remoteVersion >= 100000)
    3577        5318 :             appendPQExpBuffer(query,
    3578             :                               "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
    3579             :                               "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    3580             :                               "   pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
    3581             :                               "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    3582             :                               "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    3583             :                               "FROM pg_catalog.pg_policy pol "
    3584             :                               "WHERE polrelid = '%u'",
    3585             :                               tbinfo->dobj.catId.oid);
    3586             :         else
    3587           0 :             appendPQExpBuffer(query,
    3588             :                               "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
    3589             :                               "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    3590             :                               "   pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
    3591             :                               "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    3592             :                               "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    3593             :                               "FROM pg_catalog.pg_policy pol "
    3594             :                               "WHERE polrelid = '%u'",
    3595             :                               tbinfo->dobj.catId.oid);
    3596        5318 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3597             : 
    3598        5318 :         ntups = PQntuples(res);
    3599             : 
    3600        5318 :         if (ntups == 0)
    3601             :         {
    3602             :             /*
    3603             :              * No explicit policies to handle (only the default-deny policy,
    3604             :              * which is handled as part of the table definition).  Clean up
    3605             :              * and return.
    3606             :              */
    3607        5250 :             PQclear(res);
    3608        5250 :             continue;
    3609             :         }
    3610             : 
    3611          68 :         i_oid = PQfnumber(res, "oid");
    3612          68 :         i_tableoid = PQfnumber(res, "tableoid");
    3613          68 :         i_polname = PQfnumber(res, "polname");
    3614          68 :         i_polcmd = PQfnumber(res, "polcmd");
    3615          68 :         i_polpermissive = PQfnumber(res, "polpermissive");
    3616          68 :         i_polroles = PQfnumber(res, "polroles");
    3617          68 :         i_polqual = PQfnumber(res, "polqual");
    3618          68 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    3619             : 
    3620          68 :         polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    3621             : 
    3622         422 :         for (j = 0; j < ntups; j++)
    3623             :         {
    3624         354 :             polinfo[j].dobj.objType = DO_POLICY;
    3625         708 :             polinfo[j].dobj.catId.tableoid =
    3626         354 :                 atooid(PQgetvalue(res, j, i_tableoid));
    3627         354 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    3628         354 :             AssignDumpId(&polinfo[j].dobj);
    3629         354 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    3630         354 :             polinfo[j].poltable = tbinfo;
    3631         354 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    3632         354 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    3633             : 
    3634         354 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    3635         354 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    3636             : 
    3637         354 :             if (PQgetisnull(res, j, i_polroles))
    3638         154 :                 polinfo[j].polroles = NULL;
    3639             :             else
    3640         200 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    3641             : 
    3642         354 :             if (PQgetisnull(res, j, i_polqual))
    3643          50 :                 polinfo[j].polqual = NULL;
    3644             :             else
    3645         304 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    3646             : 
    3647         354 :             if (PQgetisnull(res, j, i_polwithcheck))
    3648         186 :                 polinfo[j].polwithcheck = NULL;
    3649             :             else
    3650         168 :                 polinfo[j].polwithcheck
    3651         168 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    3652             :         }
    3653          68 :         PQclear(res);
    3654             :     }
    3655         156 :     destroyPQExpBuffer(query);
    3656             : }
    3657             : 
    3658             : /*
    3659             :  * dumpPolicy
    3660             :  *    dump the definition of the given policy
    3661             :  */
    3662             : static void
    3663         422 : dumpPolicy(Archive *fout, PolicyInfo *polinfo)
    3664             : {
    3665         422 :     DumpOptions *dopt = fout->dopt;
    3666         422 :     TableInfo  *tbinfo = polinfo->poltable;
    3667             :     PQExpBuffer query;
    3668             :     PQExpBuffer delqry;
    3669             :     const char *cmd;
    3670             :     char       *tag;
    3671             : 
    3672         422 :     if (dopt->dataOnly)
    3673          42 :         return;
    3674             : 
    3675             :     /*
    3676             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    3677             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    3678             :      * ROW LEVEL SECURITY.
    3679             :      */
    3680         380 :     if (polinfo->polname == NULL)
    3681             :     {
    3682          62 :         query = createPQExpBuffer();
    3683             : 
    3684          62 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    3685          62 :                           fmtQualifiedDumpable(tbinfo));
    3686             : 
    3687             :         /*
    3688             :          * We must emit the ROW SECURITY object's dependency on its table
    3689             :          * explicitly, because it will not match anything in pg_depend (unlike
    3690             :          * the case for other PolicyInfo objects).
    3691             :          */
    3692          62 :         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
    3693          62 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    3694          62 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    3695             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    3696             :                                       .owner = tbinfo->rolname,
    3697             :                                       .description = "ROW SECURITY",
    3698             :                                       .section = SECTION_POST_DATA,
    3699             :                                       .createStmt = query->data,
    3700             :                                       .deps = &(tbinfo->dobj.dumpId),
    3701             :                                       .nDeps = 1));
    3702             : 
    3703          62 :         destroyPQExpBuffer(query);
    3704          62 :         return;
    3705             :     }
    3706             : 
    3707         318 :     if (polinfo->polcmd == '*')
    3708         106 :         cmd = "";
    3709         212 :     else if (polinfo->polcmd == 'r')
    3710          56 :         cmd = " FOR SELECT";
    3711         156 :     else if (polinfo->polcmd == 'a')
    3712          44 :         cmd = " FOR INSERT";
    3713         112 :     else if (polinfo->polcmd == 'w')
    3714          56 :         cmd = " FOR UPDATE";
    3715          56 :     else if (polinfo->polcmd == 'd')
    3716          56 :         cmd = " FOR DELETE";
    3717             :     else
    3718             :     {
    3719           0 :         pg_log_error("unexpected policy command type: %c",
    3720             :                      polinfo->polcmd);
    3721           0 :         exit_nicely(1);
    3722             :     }
    3723             : 
    3724         318 :     query = createPQExpBuffer();
    3725         318 :     delqry = createPQExpBuffer();
    3726             : 
    3727         318 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    3728             : 
    3729         318 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    3730         318 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    3731             : 
    3732         318 :     if (polinfo->polroles != NULL)
    3733         176 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    3734             : 
    3735         318 :     if (polinfo->polqual != NULL)
    3736         274 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    3737             : 
    3738         318 :     if (polinfo->polwithcheck != NULL)
    3739         150 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    3740             : 
    3741         318 :     appendPQExpBufferStr(query, ";\n");
    3742             : 
    3743         318 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    3744         318 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    3745             : 
    3746         318 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    3747             : 
    3748         318 :     if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
    3749         318 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    3750         318 :                      ARCHIVE_OPTS(.tag = tag,
    3751             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    3752             :                                   .owner = tbinfo->rolname,
    3753             :                                   .description = "POLICY",
    3754             :                                   .section = SECTION_POST_DATA,
    3755             :                                   .createStmt = query->data,
    3756             :                                   .dropStmt = delqry->data));
    3757             : 
    3758         318 :     free(tag);
    3759         318 :     destroyPQExpBuffer(query);
    3760         318 :     destroyPQExpBuffer(delqry);
    3761             : }
    3762             : 
    3763             : /*
    3764             :  * getPublications
    3765             :  *    get information about publications
    3766             :  */
    3767             : void
    3768         156 : getPublications(Archive *fout)
    3769             : {
    3770         156 :     DumpOptions *dopt = fout->dopt;
    3771             :     PQExpBuffer query;
    3772             :     PGresult   *res;
    3773             :     PublicationInfo *pubinfo;
    3774             :     int         i_tableoid;
    3775             :     int         i_oid;
    3776             :     int         i_pubname;
    3777             :     int         i_rolname;
    3778             :     int         i_puballtables;
    3779             :     int         i_pubinsert;
    3780             :     int         i_pubupdate;
    3781             :     int         i_pubdelete;
    3782             :     int         i_pubtruncate;
    3783             :     int         i,
    3784             :                 ntups;
    3785             : 
    3786         156 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    3787           0 :         return;
    3788             : 
    3789         156 :     query = createPQExpBuffer();
    3790             : 
    3791         156 :     resetPQExpBuffer(query);
    3792             : 
    3793             :     /* Get the publications. */
    3794         156 :     if (fout->remoteVersion >= 110000)
    3795         156 :         appendPQExpBuffer(query,
    3796             :                           "SELECT p.tableoid, p.oid, p.pubname, "
    3797             :                           "(%s p.pubowner) AS rolname, "
    3798             :                           "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
    3799             :                           "FROM pg_publication p",
    3800             :                           username_subquery);
    3801             :     else
    3802           0 :         appendPQExpBuffer(query,
    3803             :                           "SELECT p.tableoid, p.oid, p.pubname, "
    3804             :                           "(%s p.pubowner) AS rolname, "
    3805             :                           "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
    3806             :                           "FROM pg_publication p",
    3807             :                           username_subquery);
    3808             : 
    3809         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3810             : 
    3811         156 :     ntups = PQntuples(res);
    3812             : 
    3813         156 :     i_tableoid = PQfnumber(res, "tableoid");
    3814         156 :     i_oid = PQfnumber(res, "oid");
    3815         156 :     i_pubname = PQfnumber(res, "pubname");
    3816         156 :     i_rolname = PQfnumber(res, "rolname");
    3817         156 :     i_puballtables = PQfnumber(res, "puballtables");
    3818         156 :     i_pubinsert = PQfnumber(res, "pubinsert");
    3819         156 :     i_pubupdate = PQfnumber(res, "pubupdate");
    3820         156 :     i_pubdelete = PQfnumber(res, "pubdelete");
    3821         156 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    3822             : 
    3823         156 :     pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    3824             : 
    3825         272 :     for (i = 0; i < ntups; i++)
    3826             :     {
    3827         116 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    3828         232 :         pubinfo[i].dobj.catId.tableoid =
    3829         116 :             atooid(PQgetvalue(res, i, i_tableoid));
    3830         116 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    3831         116 :         AssignDumpId(&pubinfo[i].dobj);
    3832         116 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    3833         116 :         pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    3834         232 :         pubinfo[i].puballtables =
    3835         116 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    3836         232 :         pubinfo[i].pubinsert =
    3837         116 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    3838         232 :         pubinfo[i].pubupdate =
    3839         116 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    3840         232 :         pubinfo[i].pubdelete =
    3841         116 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    3842         232 :         pubinfo[i].pubtruncate =
    3843         116 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    3844             : 
    3845         116 :         if (strlen(pubinfo[i].rolname) == 0)
    3846           0 :             pg_log_warning("owner of publication \"%s\" appears to be invalid",
    3847             :                            pubinfo[i].dobj.name);
    3848             : 
    3849             :         /* Decide whether we want to dump it */
    3850         116 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    3851             :     }
    3852         156 :     PQclear(res);
    3853             : 
    3854         156 :     destroyPQExpBuffer(query);
    3855             : }
    3856             : 
    3857             : /*
    3858             :  * dumpPublication
    3859             :  *    dump the definition of the given publication
    3860             :  */
    3861             : static void
    3862         116 : dumpPublication(Archive *fout, PublicationInfo *pubinfo)
    3863             : {
    3864             :     PQExpBuffer delq;
    3865             :     PQExpBuffer query;
    3866             :     char       *qpubname;
    3867         116 :     bool        first = true;
    3868             : 
    3869         116 :     if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    3870          24 :         return;
    3871             : 
    3872          92 :     delq = createPQExpBuffer();
    3873          92 :     query = createPQExpBuffer();
    3874             : 
    3875          92 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    3876             : 
    3877          92 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    3878             :                       qpubname);
    3879             : 
    3880          92 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    3881             :                       qpubname);
    3882             : 
    3883          92 :     if (pubinfo->puballtables)
    3884          46 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    3885             : 
    3886          92 :     appendPQExpBufferStr(query, " WITH (publish = '");
    3887          92 :     if (pubinfo->pubinsert)
    3888             :     {
    3889          46 :         appendPQExpBufferStr(query, "insert");
    3890          46 :         first = false;
    3891             :     }
    3892             : 
    3893          92 :     if (pubinfo->pubupdate)
    3894             :     {
    3895          46 :         if (!first)
    3896          46 :             appendPQExpBufferStr(query, ", ");
    3897             : 
    3898          46 :         appendPQExpBufferStr(query, "update");
    3899          46 :         first = false;
    3900             :     }
    3901             : 
    3902          92 :     if (pubinfo->pubdelete)
    3903             :     {
    3904          46 :         if (!first)
    3905          46 :             appendPQExpBufferStr(query, ", ");
    3906             : 
    3907          46 :         appendPQExpBufferStr(query, "delete");
    3908          46 :         first = false;
    3909             :     }
    3910             : 
    3911          92 :     if (pubinfo->pubtruncate)
    3912             :     {
    3913          46 :         if (!first)
    3914          46 :             appendPQExpBufferStr(query, ", ");
    3915             : 
    3916          46 :         appendPQExpBufferStr(query, "truncate");
    3917          46 :         first = false;
    3918             :     }
    3919             : 
    3920          92 :     appendPQExpBufferStr(query, "');\n");
    3921             : 
    3922          92 :     ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    3923          92 :                  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    3924             :                               .owner = pubinfo->rolname,
    3925             :                               .description = "PUBLICATION",
    3926             :                               .section = SECTION_POST_DATA,
    3927             :                               .createStmt = query->data,
    3928             :                               .dropStmt = delq->data));
    3929             : 
    3930          92 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    3931         184 :         dumpComment(fout, "PUBLICATION", qpubname,
    3932          92 :                     NULL, pubinfo->rolname,
    3933             :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    3934             : 
    3935          92 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    3936         184 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    3937          92 :                      NULL, pubinfo->rolname,
    3938             :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    3939             : 
    3940          92 :     destroyPQExpBuffer(delq);
    3941          92 :     destroyPQExpBuffer(query);
    3942          92 :     free(qpubname);
    3943             : }
    3944             : 
    3945             : /*
    3946             :  * getPublicationTables
    3947             :  *    get information about publication membership for dumpable tables.
    3948             :  */
    3949             : void
    3950         156 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    3951             : {
    3952             :     PQExpBuffer query;
    3953             :     PGresult   *res;
    3954             :     PublicationRelInfo *pubrinfo;
    3955         156 :     DumpOptions *dopt = fout->dopt;
    3956             :     int         i_tableoid;
    3957             :     int         i_oid;
    3958             :     int         i_pubname;
    3959             :     int         i,
    3960             :                 j,
    3961             :                 ntups;
    3962             : 
    3963         156 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    3964           0 :         return;
    3965             : 
    3966         156 :     query = createPQExpBuffer();
    3967             : 
    3968       35736 :     for (i = 0; i < numTables; i++)
    3969             :     {
    3970       35580 :         TableInfo  *tbinfo = &tblinfo[i];
    3971             : 
    3972             :         /* Only plain tables can be aded to publications. */
    3973       35580 :         if (tbinfo->relkind != RELKIND_RELATION)
    3974       21370 :             continue;
    3975             : 
    3976             :         /*
    3977             :          * Ignore publication membership of tables whose definitions are not
    3978             :          * to be dumped.
    3979             :          */
    3980       14210 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    3981       10686 :             continue;
    3982             : 
    3983        3524 :         pg_log_info("reading publication membership for table \"%s.%s\"",
    3984             :                     tbinfo->dobj.namespace->dobj.name,
    3985             :                     tbinfo->dobj.name);
    3986             : 
    3987        3524 :         resetPQExpBuffer(query);
    3988             : 
    3989             :         /* Get the publication membership for the table. */
    3990        3524 :         appendPQExpBuffer(query,
    3991             :                           "SELECT pr.tableoid, pr.oid, p.pubname "
    3992             :                           "FROM pg_publication_rel pr, pg_publication p "
    3993             :                           "WHERE pr.prrelid = '%u'"
    3994             :                           "  AND p.oid = pr.prpubid",
    3995             :                           tbinfo->dobj.catId.oid);
    3996        3524 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3997             : 
    3998        3524 :         ntups = PQntuples(res);
    3999             : 
    4000        3524 :         if (ntups == 0)
    4001             :         {
    4002             :             /*
    4003             :              * Table is not member of any publications. Clean up and return.
    4004             :              */
    4005        3426 :             PQclear(res);
    4006        3426 :             continue;
    4007             :         }
    4008             : 
    4009          98 :         i_tableoid = PQfnumber(res, "tableoid");
    4010          98 :         i_oid = PQfnumber(res, "oid");
    4011          98 :         i_pubname = PQfnumber(res, "pubname");
    4012             : 
    4013          98 :         pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4014             : 
    4015         196 :         for (j = 0; j < ntups; j++)
    4016             :         {
    4017          98 :             pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4018         196 :             pubrinfo[j].dobj.catId.tableoid =
    4019          98 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4020          98 :             pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4021          98 :             AssignDumpId(&pubrinfo[j].dobj);
    4022          98 :             pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4023          98 :             pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4024          98 :             pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
    4025          98 :             pubrinfo[j].pubtable = tbinfo;
    4026             : 
    4027             :             /* Decide whether we want to dump it */
    4028          98 :             selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
    4029             :         }
    4030          98 :         PQclear(res);
    4031             :     }
    4032         156 :     destroyPQExpBuffer(query);
    4033             : }
    4034             : 
    4035             : /*
    4036             :  * dumpPublicationTable
    4037             :  *    dump the definition of the given publication table mapping
    4038             :  */
    4039             : static void
    4040          98 : dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
    4041             : {
    4042          98 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    4043             :     PQExpBuffer query;
    4044             :     char       *tag;
    4045             : 
    4046          98 :     if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    4047          12 :         return;
    4048             : 
    4049          86 :     tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
    4050             : 
    4051          86 :     query = createPQExpBuffer();
    4052             : 
    4053          86 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    4054          86 :                       fmtId(pubrinfo->pubname));
    4055          86 :     appendPQExpBuffer(query, " %s;\n",
    4056          86 :                       fmtQualifiedDumpable(tbinfo));
    4057             : 
    4058             :     /*
    4059             :      * There is no point in creating drop query as the drop is done by table
    4060             :      * drop.
    4061             :      */
    4062          86 :     ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    4063          86 :                  ARCHIVE_OPTS(.tag = tag,
    4064             :                               .namespace = tbinfo->dobj.namespace->dobj.name,
    4065             :                               .description = "PUBLICATION TABLE",
    4066             :                               .section = SECTION_POST_DATA,
    4067             :                               .createStmt = query->data));
    4068             : 
    4069          86 :     free(tag);
    4070          86 :     destroyPQExpBuffer(query);
    4071             : }
    4072             : 
    4073             : /*
    4074             :  * Is the currently connected user a superuser?
    4075             :  */
    4076             : static bool
    4077         156 : is_superuser(Archive *fout)
    4078             : {
    4079         156 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    4080             :     const char *val;
    4081             : 
    4082         156 :     val = PQparameterStatus(AH->connection, "is_superuser");
    4083             : 
    4084         156 :     if (val && strcmp(val, "on") == 0)
    4085         152 :         return true;
    4086             : 
    4087           4 :     return false;
    4088             : }
    4089             : 
    4090             : /*
    4091             :  * getSubscriptions
    4092             :  *    get information about subscriptions
    4093             :  */
    4094             : void
    4095         156 : getSubscriptions(Archive *fout)
    4096             : {
    4097         156 :     DumpOptions *dopt = fout->dopt;
    4098             :     PQExpBuffer query;
    4099             :     PGresult   *res;
    4100             :     SubscriptionInfo *subinfo;
    4101             :     int         i_tableoid;
    4102             :     int         i_oid;
    4103             :     int         i_subname;
    4104             :     int         i_rolname;
    4105             :     int         i_subconninfo;
    4106             :     int         i_subslotname;
    4107             :     int         i_subsynccommit;
    4108             :     int         i_subpublications;
    4109             :     int         i,
    4110             :                 ntups;
    4111             : 
    4112         156 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    4113           0 :         return;
    4114             : 
    4115         156 :     if (!is_superuser(fout))
    4116             :     {
    4117             :         int         n;
    4118             : 
    4119           4 :         res = ExecuteSqlQuery(fout,
    4120             :                               "SELECT count(*) FROM pg_subscription "
    4121             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    4122             :                               "                 WHERE datname = current_database())",
    4123             :                               PGRES_TUPLES_OK);
    4124           4 :         n = atoi(PQgetvalue(res, 0, 0));
    4125           4 :         if (n > 0)
    4126           4 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    4127           4 :         PQclear(res);
    4128           4 :         return;
    4129             :     }
    4130             : 
    4131         152 :     query = createPQExpBuffer();
    4132             : 
    4133         152 :     resetPQExpBuffer(query);
    4134             : 
    4135             :     /* Get the subscriptions in current database. */
    4136         152 :     appendPQExpBuffer(query,
    4137             :                       "SELECT s.tableoid, s.oid, s.subname,"
    4138             :                       "(%s s.subowner) AS rolname, "
    4139             :                       " s.subconninfo, s.subslotname, s.subsynccommit, "
    4140             :                       " s.subpublications "
    4141             :                       "FROM pg_subscription s "
    4142             :                       "WHERE s.subdbid = (SELECT oid FROM pg_database"
    4143             :                       "                   WHERE datname = current_database())",
    4144             :                       username_subquery);
    4145         152 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4146             : 
    4147         152 :     ntups = PQntuples(res);
    4148             : 
    4149         152 :     i_tableoid = PQfnumber(res, "tableoid");
    4150         152 :     i_oid = PQfnumber(res, "oid");
    4151         152 :     i_subname = PQfnumber(res, "subname");
    4152         152 :     i_rolname = PQfnumber(res, "rolname");
    4153         152 :     i_subconninfo = PQfnumber(res, "subconninfo");
    4154         152 :     i_subslotname = PQfnumber(res, "subslotname");
    4155         152 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    4156         152 :     i_subpublications = PQfnumber(res, "subpublications");
    4157             : 
    4158         152 :     subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    4159             : 
    4160         206 :     for (i = 0; i < ntups; i++)
    4161             :     {
    4162          54 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    4163         108 :         subinfo[i].dobj.catId.tableoid =
    4164          54 :             atooid(PQgetvalue(res, i, i_tableoid));
    4165          54 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4166          54 :         AssignDumpId(&subinfo[i].dobj);
    4167          54 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    4168          54 :         subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    4169          54 :         subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
    4170          54 :         if (PQgetisnull(res, i, i_subslotname))
    4171           0 :             subinfo[i].subslotname = NULL;
    4172             :         else
    4173          54 :             subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
    4174         108 :         subinfo[i].subsynccommit =
    4175          54 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    4176         108 :         subinfo[i].subpublications =
    4177          54 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    4178             : 
    4179          54 :         if (strlen(subinfo[i].rolname) == 0)
    4180           0 :             pg_log_warning("owner of subscription \"%s\" appears to be invalid",
    4181             :                            subinfo[i].dobj.name);
    4182             : 
    4183             :         /* Decide whether we want to dump it */
    4184          54 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    4185             :     }
    4186         152 :     PQclear(res);
    4187             : 
    4188         152 :     destroyPQExpBuffer(query);
    4189             : }
    4190             : 
    4191             : /*
    4192             :  * dumpSubscription
    4193             :  *    dump the definition of the given subscription
    4194             :  */
    4195             : static void
    4196          54 : dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
    4197             : {
    4198             :     PQExpBuffer delq;
    4199             :     PQExpBuffer query;
    4200             :     PQExpBuffer publications;
    4201             :     char       *qsubname;
    4202          54 :     char      **pubnames = NULL;
    4203          54 :     int         npubnames = 0;
    4204             :     int         i;
    4205             : 
    4206          54 :     if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    4207           8 :         return;
    4208             : 
    4209          46 :     delq = createPQExpBuffer();
    4210          46 :     query = createPQExpBuffer();
    4211             : 
    4212          46 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    4213             : 
    4214          46 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    4215             :                       qsubname);
    4216             : 
    4217          46 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    4218             :                       qsubname);
    4219          46 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    4220             : 
    4221             :     /* Build list of quoted publications and append them to query. */
    4222          46 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    4223             :     {
    4224           0 :         pg_log_warning("could not parse subpublications array");
    4225           0 :         if (pubnames)
    4226           0 :             free(pubnames);
    4227           0 :         pubnames = NULL;
    4228           0 :         npubnames = 0;
    4229             :     }
    4230             : 
    4231          46 :     publications = createPQExpBuffer();
    4232          92 :     for (i = 0; i < npubnames; i++)
    4233             :     {
    4234          46 :         if (i > 0)
    4235           0 :             appendPQExpBufferStr(publications, ", ");
    4236             : 
    4237          46 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    4238             :     }
    4239             : 
    4240          46 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    4241          46 :     if (subinfo->subslotname)
    4242          46 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    4243             :     else
    4244           0 :         appendPQExpBufferStr(query, "NONE");
    4245             : 
    4246          46 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    4247           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    4248             : 
    4249          46 :     appendPQExpBufferStr(query, ");\n");
    4250             : 
    4251          46 :     ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    4252          46 :                  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    4253             :                               .owner = subinfo->rolname,
    4254             :                               .description = "SUBSCRIPTION",
    4255             :                               .section = SECTION_POST_DATA,
    4256             :                               .createStmt = query->data,
    4257             :                               .dropStmt = delq->data));
    4258             : 
    4259          46 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4260          92 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    4261          46 :                     NULL, subinfo->rolname,
    4262             :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    4263             : 
    4264          46 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4265          92 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    4266          46 :                      NULL, subinfo->rolname,
    4267             :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    4268             : 
    4269          46 :     destroyPQExpBuffer(publications);
    4270          46 :     if (pubnames)
    4271          46 :         free(pubnames);
    4272             : 
    4273          46 :     destroyPQExpBuffer(delq);
    4274          46 :     destroyPQExpBuffer(query);
    4275          46 :     free(qsubname);
    4276             : }
    4277             : 
    4278             : static void
    4279        1422 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    4280             :                                          PQExpBuffer upgrade_buffer,
    4281             :                                          Oid pg_type_oid,
    4282             :                                          bool force_array_type)
    4283             : {
    4284        1422 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    4285             :     PGresult   *res;
    4286             :     Oid         pg_type_array_oid;
    4287             : 
    4288        1422 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    4289        1422 :     appendPQExpBuffer(upgrade_buffer,
    4290             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    4291             :                       pg_type_oid);
    4292             : 
    4293             :     /* we only support old >= 8.3 for binary upgrades */
    4294        1422 :     appendPQExpBuffer(upgrade_query,
    4295             :                       "SELECT typarray "
    4296             :                       "FROM pg_catalog.pg_type "
    4297             :                       "WHERE oid = '%u'::pg_catalog.oid;",
    4298             :                       pg_type_oid);
    4299             : 
    4300        1422 :     res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    4301             : 
    4302        1422 :     pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    4303             : 
    4304        1422 :     PQclear(res);
    4305             : 
    4306        1422 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    4307             :     {
    4308             :         /*
    4309             :          * If the old version didn't assign an array type, but the new version
    4310             :          * does, we must select an unused type OID to assign.  This currently
    4311             :          * only happens for domains, when upgrading pre-v11 to v11 and up.
    4312             :          *
    4313             :          * Note: local state here is kind of ugly, but we must have some,
    4314             :          * since we mustn't choose the same unused OID more than once.
    4315             :          */
    4316             :         static Oid  next_possible_free_oid = FirstNormalObjectId;
    4317             :         bool        is_dup;
    4318             : 
    4319             :         do
    4320             :         {
    4321           0 :             ++next_possible_free_oid;
    4322           0 :             printfPQExpBuffer(upgrade_query,
    4323             :                               "SELECT EXISTS(SELECT 1 "
    4324             :                               "FROM pg_catalog.pg_type "
    4325             :                               "WHERE oid = '%u'::pg_catalog.oid);",
    4326             :                               next_possible_free_oid);
    4327           0 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    4328           0 :             is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    4329           0 :             PQclear(res);
    4330           0 :         } while (is_dup);
    4331             : 
    4332           0 :         pg_type_array_oid = next_possible_free_oid;
    4333             :     }
    4334             : 
    4335        1422 :     if (OidIsValid(pg_type_array_oid))
    4336             :     {
    4337        1322 :         appendPQExpBufferStr(upgrade_buffer,
    4338             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    4339        1322 :         appendPQExpBuffer(upgrade_buffer,
    4340             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    4341             :                           pg_type_array_oid);
    4342             :     }
    4343             : 
    4344        1422 :     destroyPQExpBuffer(upgrade_query);
    4345        1422 : }
    4346             : 
    4347             : static bool
    4348        1298 : binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
    4349             :                                         PQExpBuffer upgrade_buffer,
    4350             :                                         Oid pg_rel_oid)
    4351             : {
    4352        1298 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    4353             :     PGresult   *upgrade_res;
    4354             :     Oid         pg_type_oid;
    4355        1298 :     bool        toast_set = false;
    4356             : 
    4357             :     /*
    4358             :      * We only support old >= 8.3 for binary upgrades.
    4359             :      *
    4360             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    4361             :      * that versions 10 and 11 have them, but 12 does not, so emitting them
    4362             :      * causes the upgrade to fail.
    4363             :      */
    4364        1298 :     appendPQExpBuffer(upgrade_query,
    4365             :                       "SELECT c.reltype AS crel, t.reltype AS trel "
    4366             :                       "FROM pg_catalog.pg_class c "
    4367             :                       "LEFT JOIN pg_catalog.pg_class t ON "
    4368             :                       "  (c.reltoastrelid = t.oid AND c.relkind <> '%c') "
    4369             :                       "WHERE c.oid = '%u'::pg_catalog.oid;",
    4370             :                       RELKIND_PARTITIONED_TABLE, pg_rel_oid);
    4371             : 
    4372        1298 :     upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    4373             : 
    4374        1298 :     pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
    4375             : 
    4376        1298 :     binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    4377             :                                              pg_type_oid, false);
    4378             : 
    4379        1298 :     if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
    4380             :     {
    4381             :         /* Toast tables do not have pg_type array rows */
    4382         430 :         Oid         pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
    4383             :                                                           PQfnumber(upgrade_res, "trel")));
    4384             : 
    4385         430 :         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
    4386         430 :         appendPQExpBuffer(upgrade_buffer,
    4387             :                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    4388             :                           pg_type_toast_oid);
    4389             : 
    4390         430 :         toast_set = true;
    4391             :     }
    4392             : 
    4393        1298 :     PQclear(upgrade_res);
    4394        1298 :     destroyPQExpBuffer(upgrade_query);
    4395             : 
    4396        1298 :     return toast_set;
    4397             : }
    4398             : 
    4399             : static void
    4400        1772 : binary_upgrade_set_pg_class_oids(Archive *fout,
    4401             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
    4402             :                                  bool is_index)
    4403             : {
    4404        1772 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    4405             :     PGresult   *upgrade_res;
    4406             :     Oid         pg_class_reltoastrelid;
    4407             :     Oid         pg_index_indexrelid;
    4408             : 
    4409        1772 :     appendPQExpBuffer(upgrade_query,
    4410             :                       "SELECT c.reltoastrelid, i.indexrelid "
    4411             :                       "FROM pg_catalog.pg_class c LEFT JOIN "
    4412             :                       "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    4413             :                       "WHERE c.oid = '%u'::pg_catalog.oid;",
    4414             :                       pg_class_oid);
    4415             : 
    4416        1772 :     upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    4417             : 
    4418        1772 :     pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
    4419        1772 :     pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
    4420             : 
    4421        1772 :     appendPQExpBufferStr(upgrade_buffer,
    4422             :                          "\n-- For binary upgrade, must preserve pg_class oids\n");
    4423             : 
    4424        1772 :     if (!is_index)
    4425             :     {
    4426        1334 :         appendPQExpBuffer(upgrade_buffer,
    4427             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    4428             :                           pg_class_oid);
    4429             :         /* only tables have toast tables, not indexes */
    4430        1334 :         if (OidIsValid(pg_class_reltoastrelid))
    4431             :         {
    4432             :             /*
    4433             :              * One complexity is that the table definition might not require
    4434             :              * the creation of a TOAST table, and the TOAST table might have
    4435             :              * been created long after table creation, when the table was
    4436             :              * loaded with wide data.  By setting the TOAST oid we force
    4437             :              * creation of the TOAST heap and TOAST index by the backend so we
    4438             :              * can cleanly copy the files during binary upgrade.
    4439             :              */
    4440             : 
    4441         430 :             appendPQExpBuffer(upgrade_buffer,
    4442             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    4443             :                               pg_class_reltoastrelid);
    4444             : 
    4445             :             /* every toast table has an index */
    4446         430 :             appendPQExpBuffer(upgrade_buffer,
    4447             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    4448             :                               pg_index_indexrelid);
    4449             :         }
    4450             :     }
    4451             :     else
    4452         438 :         appendPQExpBuffer(upgrade_buffer,
    4453             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    4454             :                           pg_class_oid);
    4455             : 
    4456        1772 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    4457             : 
    4458        1772 :     PQclear(upgrade_res);
    4459        1772 :     destroyPQExpBuffer(upgrade_query);
    4460        1772 : }
    4461             : 
    4462             : /*
    4463             :  * If the DumpableObject is a member of an extension, add a suitable
    4464             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    4465             :  *
    4466             :  * For somewhat historical reasons, objname should already be quoted,
    4467             :  * but not objnamespace (if any).
    4468             :  */
    4469             : static void
    4470        2118 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    4471             :                                 DumpableObject *dobj,
    4472             :                                 const char *objtype,
    4473             :                                 const char *objname,
    4474             :                                 const char *objnamespace)
    4475             : {
    4476        2118 :     DumpableObject *extobj = NULL;
    4477             :     int         i;
    4478             : 
    4479        2118 :     if (!dobj->ext_member)
    4480        2092 :         return;
    4481             : 
    4482             :     /*
    4483             :      * Find the parent extension.  We could avoid this search if we wanted to
    4484             :      * add a link field to DumpableObject, but the space costs of that would
    4485             :      * be considerable.  We assume that member objects could only have a
    4486             :      * direct dependency on their own extension, not any others.
    4487             :      */
    4488          26 :     for (i = 0; i < dobj->nDeps; i++)
    4489             :     {
    4490          26 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    4491          26 :         if (extobj && extobj->objType == DO_EXTENSION)
    4492          26 :             break;
    4493           0 :         extobj = NULL;
    4494             :     }
    4495          26 :     if (extobj == NULL)
    4496           0 :         fatal("could not find parent extension for %s %s",
    4497             :               objtype, objname);
    4498             : 
    4499          26 :     appendPQExpBufferStr(upgrade_buffer,
    4500             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    4501          26 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    4502          26 :                       fmtId(extobj->name),
    4503             :                       objtype);
    4504          26 :     if (objnamespace && *objnamespace)
    4505          20 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    4506          26 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    4507             : }
    4508             : 
    4509             : /*
    4510             :  * getNamespaces:
    4511             :  *    read all namespaces in the system catalogs and return them in the
    4512             :  * NamespaceInfo* structure
    4513             :  *
    4514             :  *  numNamespaces is set to the number of namespaces read in
    4515             :  */
    4516             : NamespaceInfo *
    4517         158 : getNamespaces(Archive *fout, int *numNamespaces)
    4518             : {
    4519         158 :     DumpOptions *dopt = fout->dopt;
    4520             :     PGresult   *res;
    4521             :     int         ntups;
    4522             :     int         i;
    4523             :     PQExpBuffer query;
    4524             :     NamespaceInfo *nsinfo;
    4525             :     int         i_tableoid;
    4526             :     int         i_oid;
    4527             :     int         i_nspname;
    4528             :     int         i_rolname;
    4529             :     int         i_nspacl;
    4530             :     int         i_rnspacl;
    4531             :     int         i_initnspacl;
    4532             :     int         i_initrnspacl;
    4533             : 
    4534         158 :     query = createPQExpBuffer();
    4535             : 
    4536             :     /*
    4537             :      * we fetch all namespaces including system ones, so that every object we
    4538             :      * read in can be linked to a containing namespace.
    4539             :      */
    4540         158 :     if (fout->remoteVersion >= 90600)
    4541             :     {
    4542         158 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    4543         158 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    4544         158 :         PQExpBuffer init_acl_subquery = createPQExpBuffer();
    4545         158 :         PQExpBuffer init_racl_subquery = createPQExpBuffer();
    4546             : 
    4547         158 :         buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
    4548             :                         init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
    4549         158 :                         dopt->binary_upgrade);
    4550             : 
    4551         158 :         appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
    4552             :                           "(%s nspowner) AS rolname, "
    4553             :                           "%s as nspacl, "
    4554             :                           "%s as rnspacl, "
    4555             :                           "%s as initnspacl, "
    4556             :                           "%s as initrnspacl "
    4557             :                           "FROM pg_namespace n "
    4558             :                           "LEFT JOIN pg_init_privs pip "
    4559             :                           "ON (n.oid = pip.objoid "
    4560             :                           "AND pip.classoid = 'pg_namespace'::regclass "
    4561             :                           "AND pip.objsubid = 0",
    4562             :                           username_subquery,
    4563             :                           acl_subquery->data,
    4564             :                           racl_subquery->data,
    4565             :                           init_acl_subquery->data,
    4566             :                           init_racl_subquery->data);
    4567             : 
    4568         158 :         appendPQExpBufferStr(query, ") ");
    4569             : 
    4570         158 :         destroyPQExpBuffer(acl_subquery);
    4571         158 :         destroyPQExpBuffer(racl_subquery);
    4572         158 :         destroyPQExpBuffer(init_acl_subquery);
    4573         158 :         destroyPQExpBuffer(init_racl_subquery);
    4574             :     }
    4575             :     else
    4576           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
    4577             :                           "(%s nspowner) AS rolname, "
    4578             :                           "nspacl, NULL as rnspacl, "
    4579             :                           "NULL AS initnspacl, NULL as initrnspacl "
    4580             :                           "FROM pg_namespace",
    4581             :                           username_subquery);
    4582             : 
    4583         158 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4584             : 
    4585         158 :     ntups = PQntuples(res);
    4586             : 
    4587         158 :     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    4588             : 
    4589         158 :     i_tableoid = PQfnumber(res, "tableoid");
    4590         158 :     i_oid = PQfnumber(res, "oid");
    4591         158 :     i_nspname = PQfnumber(res, "nspname");
    4592         158 :     i_rolname = PQfnumber(res, "rolname");
    4593         158 :     i_nspacl = PQfnumber(res, "nspacl");
    4594         158 :     i_rnspacl = PQfnumber(res, "rnspacl");
    4595         158 :     i_initnspacl = PQfnumber(res, "initnspacl");
    4596         158 :     i_initrnspacl = PQfnumber(res, "initrnspacl");
    4597             : 
    4598        1410 :     for (i = 0; i < ntups; i++)
    4599             :     {
    4600        1252 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    4601        1252 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    4602        1252 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4603        1252 :         AssignDumpId(&nsinfo[i].dobj);
    4604        1252 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    4605        1252 :         nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    4606        1252 :         nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    4607        1252 :         nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
    4608        1252 :         nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
    4609        1252 :         nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
    4610             : 
    4611             :         /* Decide whether to dump this namespace */
    4612        1252 :         selectDumpableNamespace(&nsinfo[i], fout);
    4613             : 
    4614             :         /*
    4615             :          * Do not try to dump ACL if the ACL is empty or the default.
    4616             :          *
    4617             :          * This is useful because, for some schemas/objects, the only
    4618             :          * component we are going to try and dump is the ACL and if we can
    4619             :          * remove that then 'dump' goes to zero/false and we don't consider
    4620             :          * this object for dumping at all later on.
    4621             :          */
    4622        2226 :         if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
    4623        1948 :             PQgetisnull(res, i, i_initnspacl) &&
    4624         974 :             PQgetisnull(res, i, i_initrnspacl))
    4625         974 :             nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    4626             : 
    4627        1252 :         if (strlen(nsinfo[i].rolname) == 0)
    4628           0 :             pg_log_warning("owner of schema \"%s\" appears to be invalid",
    4629             :                            nsinfo[i].dobj.name);
    4630             :     }
    4631             : 
    4632         158 :     PQclear(res);
    4633         158 :     destroyPQExpBuffer(query);
    4634             : 
    4635         158 :     *numNamespaces = ntups;
    4636             : 
    4637         158 :     return nsinfo;
    4638             : }
    4639             : 
    4640             : /*
    4641             :  * findNamespace:
    4642             :  *      given a namespace OID, look up the info read by getNamespaces
    4643             :  */
    4644             : static NamespaceInfo *
    4645      304270 : findNamespace(Archive *fout, Oid nsoid)
    4646             : {
    4647             :     NamespaceInfo *nsinfo;
    4648             : 
    4649      304270 :     nsinfo = findNamespaceByOid(nsoid);
    4650      304270 :     if (nsinfo == NULL)
    4651           0 :         fatal("schema with OID %u does not exist", nsoid);
    4652      304270 :     return nsinfo;
    4653             : }
    4654             : 
    4655             : /*
    4656             :  * getExtensions:
    4657             :  *    read all extensions in the system catalogs and return them in the
    4658             :  * ExtensionInfo* structure
    4659             :  *
    4660             :  *  numExtensions is set to the number of extensions read in
    4661             :  */
    4662             : ExtensionInfo *
    4663         158 : getExtensions(Archive *fout, int *numExtensions)
    4664             : {
    4665         158 :     DumpOptions *dopt = fout->dopt;
    4666             :     PGresult   *res;
    4667             :     int         ntups;
    4668             :     int         i;
    4669             :     PQExpBuffer query;
    4670             :     ExtensionInfo *extinfo;
    4671             :     int         i_tableoid;
    4672             :     int         i_oid;
    4673             :     int         i_extname;
    4674             :     int         i_nspname;
    4675             :     int         i_extrelocatable;
    4676             :     int         i_extversion;
    4677             :     int         i_extconfig;
    4678             :     int         i_extcondition;
    4679             : 
    4680             :     /*
    4681             :      * Before 9.1, there are no extensions.
    4682             :      */
    4683         158 :     if (fout->remoteVersion < 90100)
    4684             :     {
    4685           0 :         *numExtensions = 0;
    4686           0 :         return NULL;
    4687             :     }
    4688             : 
    4689         158 :     query = createPQExpBuffer();
    4690             : 
    4691         158 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    4692             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    4693             :                          "FROM pg_extension x "
    4694             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    4695             : 
    4696         158 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4697             : 
    4698         158 :     ntups = PQntuples(res);
    4699             : 
    4700         158 :     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    4701             : 
    4702         158 :     i_tableoid = PQfnumber(res, "tableoid");
    4703         158 :     i_oid = PQfnumber(res, "oid");
    4704         158 :     i_extname = PQfnumber(res, "extname");
    4705         158 :     i_nspname = PQfnumber(res, "nspname");
    4706         158 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    4707         158 :     i_extversion = PQfnumber(res, "extversion");
    4708         158 :     i_extconfig = PQfnumber(res, "extconfig");
    4709         158 :     i_extcondition = PQfnumber(res, "extcondition");
    4710             : 
    4711         348 :     for (i = 0; i < ntups; i++)
    4712             :     {
    4713         190 :         extinfo[i].dobj.objType = DO_EXTENSION;
    4714         190 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    4715         190 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4716         190 :         AssignDumpId(&extinfo[i].dobj);
    4717         190 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    4718         190 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    4719         190 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    4720         190 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    4721         190 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    4722         190 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    4723             : 
    4724             :         /* Decide whether we want to dump it */
    4725         190 :         selectDumpableExtension(&(extinfo[i]), dopt);
    4726             :     }
    4727             : 
    4728         158 :     PQclear(res);
    4729         158 :     destroyPQExpBuffer(query);
    4730             : 
    4731         158 :     *numExtensions = ntups;
    4732             : 
    4733         158 :     return extinfo;
    4734             : }
    4735             : 
    4736             : /*
    4737             :  * getTypes:
    4738             :  *    read all types in the system catalogs and return them in the
    4739             :  * TypeInfo* structure
    4740             :  *
    4741             :  *  numTypes is set to the number of types read in
    4742             :  *
    4743             :  * NB: this must run after getFuncs() because we assume we can do
    4744             :  * findFuncByOid().
    4745             :  */
    4746             : TypeInfo *
    4747         156 : getTypes(Archive *fout, int *numTypes)
    4748             : {
    4749         156 :     DumpOptions *dopt = fout->dopt;
    4750             :     PGresult   *res;
    4751             :     int         ntups;
    4752             :     int         i;
    4753         156 :     PQExpBuffer query = createPQExpBuffer();
    4754             :     TypeInfo   *tyinfo;
    4755             :     ShellTypeInfo *stinfo;
    4756             :     int         i_tableoid;
    4757             :     int         i_oid;
    4758             :     int         i_typname;
    4759             :     int         i_typnamespace;
    4760             :     int         i_typacl;
    4761             :     int         i_rtypacl;
    4762             :     int         i_inittypacl;
    4763             :     int         i_initrtypacl;
    4764             :     int         i_rolname;
    4765             :     int         i_typelem;
    4766             :     int         i_typrelid;
    4767             :     int         i_typrelkind;
    4768             :     int         i_typtype;
    4769             :     int         i_typisdefined;
    4770             :     int         i_isarray;
    4771             : 
    4772             :     /*
    4773             :      * we include even the built-in types because those may be used as array
    4774             :      * elements by user-defined types
    4775             :      *
    4776             :      * we filter out the built-in types when we dump out the types
    4777             :      *
    4778             :      * same approach for undefined (shell) types and array types
    4779             :      *
    4780             :      * Note: as of 8.3 we can reliably detect whether a type is an
    4781             :      * auto-generated array type by checking the element type's typarray.
    4782             :      * (Before that the test is capable of generating false positives.) We
    4783             :      * still check for name beginning with '_', though, so as to avoid the
    4784             :      * cost of the subselect probe for all standard types.  This would have to
    4785             :      * be revisited if the backend ever allows renaming of array types.
    4786             :      */
    4787             : 
    4788         156 :     if (fout->remoteVersion >= 90600)
    4789             :     {
    4790         156 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    4791         156 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    4792         156 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    4793         156 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    4794             : 
    4795         156 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    4796             :                         initracl_subquery, "t.typacl", "t.typowner", "'T'",
    4797         156 :                         dopt->binary_upgrade);
    4798             : 
    4799         156 :         appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
    4800             :                           "t.typnamespace, "
    4801             :                           "%s AS typacl, "
    4802             :                           "%s AS rtypacl, "
    4803             :                           "%s AS inittypacl, "
    4804             :                           "%s AS initrtypacl, "
    4805             :                           "(%s t.typowner) AS rolname, "
    4806             :                           "t.typelem, t.typrelid, "
    4807             :                           "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
    4808             :                           "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
    4809             :                           "t.typtype, t.typisdefined, "
    4810             :                           "t.typname[0] = '_' AND t.typelem != 0 AND "
    4811             :                           "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
    4812             :                           "FROM pg_type t "
    4813             :                           "LEFT JOIN pg_init_privs pip ON "
    4814             :                           "(t.oid = pip.objoid "
    4815             :                           "AND pip.classoid = 'pg_type'::regclass "
    4816             :                           "AND pip.objsubid = 0) ",
    4817             :                           acl_subquery->data,
    4818             :                           racl_subquery->data,
    4819             :                           initacl_subquery->data,
    4820             :                           initracl_subquery->data,
    4821             :                           username_subquery);
    4822             : 
    4823         156 :         destroyPQExpBuffer(acl_subquery);
    4824         156 :         destroyPQExpBuffer(racl_subquery);
    4825         156 :         destroyPQExpBuffer(initacl_subquery);
    4826         156 :         destroyPQExpBuffer(initracl_subquery);
    4827             :     }
    4828           0 :     else if (fout->remoteVersion >= 90200)
    4829             :     {
    4830           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
    4831             :                           "typnamespace, typacl, NULL as rtypacl, "
    4832             :                           "NULL AS inittypacl, NULL AS initrtypacl, "
    4833             :                           "(%s typowner) AS rolname, "
    4834             :                           "typelem, typrelid, "
    4835             :                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    4836             :                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    4837             :                           "typtype, typisdefined, "
    4838             :                           "typname[0] = '_' AND typelem != 0 AND "
    4839             :                           "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    4840             :                           "FROM pg_type",
    4841             :                           username_subquery);
    4842             :     }
    4843           0 :     else if (fout->remoteVersion >= 80300)
    4844             :     {
    4845           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
    4846             :                           "typnamespace, NULL AS typacl, NULL as rtypacl, "
    4847             :                           "NULL AS inittypacl, NULL AS initrtypacl, "
    4848             :                           "(%s typowner) AS rolname, "
    4849             :                           "typelem, typrelid, "
    4850             :                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    4851             :                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    4852             :                           "typtype, typisdefined, "
    4853             :                           "typname[0] = '_' AND typelem != 0 AND "
    4854             :                           "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    4855             :                           "FROM pg_type",
    4856             :                           username_subquery);
    4857             :     }
    4858             :     else
    4859             :     {
    4860           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
    4861             :                           "typnamespace, NULL AS typacl, NULL as rtypacl, "
    4862             :                           "NULL AS inittypacl, NULL AS initrtypacl, "
    4863             :                           "(%s typowner) AS rolname, "
    4864             :                           "typelem, typrelid, "
    4865             :                           "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    4866             :                           "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    4867             :                           "typtype, typisdefined, "
    4868             :                           "typname[0] = '_' AND typelem != 0 AS isarray "
    4869             :                           "FROM pg_type",
    4870             :                           username_subquery);
    4871             :     }
    4872             : 
    4873         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4874             : 
    4875         156 :     ntups = PQntuples(res);
    4876             : 
    4877         156 :     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    4878             : 
    4879         156 :     i_tableoid = PQfnumber(res, "tableoid");
    4880         156 :     i_oid = PQfnumber(res, "oid");
    4881         156 :     i_typname = PQfnumber(res, "typname");
    4882         156 :     i_typnamespace = PQfnumber(res, "typnamespace");
    4883         156 :     i_typacl = PQfnumber(res, "typacl");
    4884         156 :     i_rtypacl = PQfnumber(res, "rtypacl");
    4885         156 :     i_inittypacl = PQfnumber(res, "inittypacl");
    4886         156 :     i_initrtypacl = PQfnumber(res, "initrtypacl");
    4887         156 :     i_rolname = PQfnumber(res, "rolname");
    4888         156 :     i_typelem = PQfnumber(res, "typelem");
    4889         156 :     i_typrelid = PQfnumber(res, "typrelid");
    4890         156 :     i_typrelkind = PQfnumber(res, "typrelkind");
    4891         156 :     i_typtype = PQfnumber(res, "typtype");
    4892         156 :     i_typisdefined = PQfnumber(res, "typisdefined");
    4893         156 :     i_isarray = PQfnumber(res, "isarray");
    4894             : 
    4895       76014 :     for (i = 0; i < ntups; i++)
    4896             :     {
    4897       75858 :         tyinfo[i].dobj.objType = DO_TYPE;
    4898       75858 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    4899       75858 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4900       75858 :         AssignDumpId(&tyinfo[i].dobj);
    4901       75858 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    4902      151716 :         tyinfo[i].dobj.namespace =
    4903       75858 :             findNamespace(fout,
    4904       75858 :                           atooid(PQgetvalue(res, i, i_typnamespace)));
    4905       75858 :         tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    4906       75858 :         tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
    4907       75858 :         tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
    4908       75858 :         tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
    4909       75858 :         tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
    4910       75858 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    4911       75858 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    4912       75858 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    4913       75858 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    4914       75858 :         tyinfo[i].shellType = NULL;
    4915             : 
    4916       75858 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    4917       75794 :             tyinfo[i].isDefined = true;
    4918             :         else
    4919          64 :             tyinfo[i].isDefined = false;
    4920             : 
    4921       75858 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    4922       17262 :             tyinfo[i].isArray = true;
    4923             :         else
    4924       58596 :             tyinfo[i].isArray = false;
    4925             : 
    4926             :         /* Decide whether we want to dump it */
    4927       75858 :         selectDumpableType(&tyinfo[i], fout);
    4928             : 
    4929             :         /* Do not try to dump ACL if no ACL exists. */
    4930      151484 :         if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
    4931      151250 :             PQgetisnull(res, i, i_inittypacl) &&
    4932       75624 :             PQgetisnull(res, i, i_initrtypacl))
    4933       75624 :             tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    4934             : 
    4935             :         /*
    4936             :          * If it's a domain, fetch info about its constraints, if any
    4937             :          */
    4938       75858 :         tyinfo[i].nDomChecks = 0;
    4939       75858 :         tyinfo[i].domChecks = NULL;
    4940       86980 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    4941       11122 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    4942         144 :             getDomainConstraints(fout, &(tyinfo[i]));
    4943             : 
    4944             :         /*
    4945             :          * If it's a base type, make a DumpableObject representing a shell
    4946             :          * definition of the type.  We will need to dump that ahead of the I/O
    4947             :          * functions for the type.  Similarly, range types need a shell
    4948             :          * definition in case they have a canonicalize function.
    4949             :          *
    4950             :          * Note: the shell type doesn't have a catId.  You might think it
    4951             :          * should copy the base type's catId, but then it might capture the
    4952             :          * pg_depend entries for the type, which we don't want.
    4953             :          */
    4954       86980 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    4955       16754 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    4956        5632 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    4957             :         {
    4958        5610 :             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    4959        5610 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    4960        5610 :             stinfo->dobj.catId = nilCatalogId;
    4961        5610 :             AssignDumpId(&stinfo->dobj);
    4962        5610 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    4963        5610 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    4964        5610 :             stinfo->baseType = &(tyinfo[i]);
    4965        5610 :             tyinfo[i].shellType = stinfo;
    4966             : 
    4967             :             /*
    4968             :              * Initially mark the shell type as not to be dumped.  We'll only
    4969             :              * dump it if the I/O or canonicalize functions need to be dumped;
    4970             :              * this is taken care of while sorting dependencies.
    4971             :              */
    4972        5610 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    4973             :         }
    4974             : 
    4975       75858 :         if (strlen(tyinfo[i].rolname) == 0)
    4976           0 :             pg_log_warning("owner of data type \"%s\" appears to be invalid",
    4977             :                            tyinfo[i].dobj.name);
    4978             :     }
    4979             : 
    4980         156 :     *numTypes = ntups;
    4981             : 
    4982         156 :     PQclear(res);
    4983             : 
    4984         156 :     destroyPQExpBuffer(query);
    4985             : 
    4986         156 :     return tyinfo;
    4987             : }
    4988             : 
    4989             : /*
    4990             :  * getOperators:
    4991             :  *    read all operators in the system catalogs and return them in the
    4992             :  * OprInfo* structure
    4993             :  *
    4994             :  *  numOprs is set to the number of operators read in
    4995             :  */
    4996             : OprInfo *
    4997         156 : getOperators(Archive *fout, int *numOprs)
    4998             : {
    4999             :     PGresult   *res;
    5000             :     int         ntups;
    5001             :     int         i;
    5002         156 :     PQExpBuffer query = createPQExpBuffer();
    5003             :     OprInfo    *oprinfo;
    5004             :     int         i_tableoid;
    5005             :     int         i_oid;
    5006             :     int         i_oprname;
    5007             :     int         i_oprnamespace;
    5008             :     int         i_rolname;
    5009             :     int         i_oprkind;
    5010             :     int         i_oprcode;
    5011             : 
    5012             :     /*
    5013             :      * find all operators, including builtin operators; we filter out
    5014             :      * system-defined operators at dump-out time.
    5015             :      */
    5016             : 
    5017         156 :     appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
    5018             :                       "oprnamespace, "
    5019             :                       "(%s oprowner) AS rolname, "
    5020             :                       "oprkind, "
    5021             :                       "oprcode::oid AS oprcode "
    5022             :                       "FROM pg_operator",
    5023             :                       username_subquery);
    5024             : 
    5025         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5026             : 
    5027         156 :     ntups = PQntuples(res);
    5028         156 :     *numOprs = ntups;
    5029             : 
    5030         156 :     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    5031             : 
    5032         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5033         156 :     i_oid = PQfnumber(res, "oid");
    5034         156 :     i_oprname = PQfnumber(res, "oprname");
    5035         156 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    5036         156 :     i_rolname = PQfnumber(res, "rolname");
    5037         156 :     i_oprkind = PQfnumber(res, "oprkind");
    5038         156 :     i_oprcode = PQfnumber(res, "oprcode");
    5039             : 
    5040      121676 :     for (i = 0; i < ntups; i++)
    5041             :     {
    5042      121520 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    5043      121520 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5044      121520 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5045      121520 :         AssignDumpId(&oprinfo[i].dobj);
    5046      121520 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    5047      243040 :         oprinfo[i].dobj.namespace =
    5048      121520 :             findNamespace(fout,
    5049      121520 :                           atooid(PQgetvalue(res, i, i_oprnamespace)));
    5050      121520 :         oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    5051      121520 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    5052      121520 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    5053             : 
    5054             :         /* Decide whether we want to dump it */
    5055      121520 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    5056             : 
    5057             :         /* Operators do not currently have ACLs. */
    5058      121520 :         oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    5059             : 
    5060      121520 :         if (strlen(oprinfo[i].rolname) == 0)
    5061           0 :             pg_log_warning("owner of operator \"%s\" appears to be invalid",
    5062             :                            oprinfo[i].dobj.name);
    5063             :     }
    5064             : 
    5065         156 :     PQclear(res);
    5066             : 
    5067         156 :     destroyPQExpBuffer(query);
    5068             : 
    5069         156 :     return oprinfo;
    5070             : }
    5071             : 
    5072             : /*
    5073             :  * getCollations:
    5074             :  *    read all collations in the system catalogs and return them in the
    5075             :  * CollInfo* structure
    5076             :  *
    5077             :  *  numCollations is set to the number of collations read in
    5078             :  */
    5079             : CollInfo *
    5080         156 : getCollations(Archive *fout, int *numCollations)
    5081             : {
    5082             :     PGresult   *res;
    5083             :     int         ntups;
    5084             :     int         i;
    5085             :     PQExpBuffer query;
    5086             :     CollInfo   *collinfo;
    5087             :     int         i_tableoid;
    5088             :     int         i_oid;
    5089             :     int         i_collname;
    5090             :     int         i_collnamespace;
    5091             :     int         i_rolname;
    5092             : 
    5093             :     /* Collations didn't exist pre-9.1 */
    5094         156 :     if (fout->remoteVersion < 90100)
    5095             :     {
    5096           0 :         *numCollations = 0;
    5097           0 :         return NULL;
    5098             :     }
    5099             : 
    5100         156 :     query = createPQExpBuffer();
    5101             : 
    5102             :     /*
    5103             :      * find all collations, including builtin collations; we filter out
    5104             :      * system-defined collations at dump-out time.
    5105             :      */
    5106             : 
    5107         156 :     appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
    5108             :                       "collnamespace, "
    5109             :                       "(%s collowner) AS rolname "
    5110             :                       "FROM pg_collation",
    5111             :                       username_subquery);
    5112             : 
    5113         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5114             : 
    5115         156 :     ntups = PQntuples(res);
    5116         156 :     *numCollations = ntups;
    5117             : 
    5118         156 :     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    5119             : 
    5120         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5121         156 :     i_oid = PQfnumber(res, "oid");
    5122         156 :     i_collname = PQfnumber(res, "collname");
    5123         156 :     i_collnamespace = PQfnumber(res, "collnamespace");
    5124         156 :     i_rolname = PQfnumber(res, "rolname");
    5125             : 
    5126        1306 :     for (i = 0; i < ntups; i++)
    5127             :     {
    5128        1150 :         collinfo[i].dobj.objType = DO_COLLATION;
    5129        1150 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5130        1150 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5131        1150 :         AssignDumpId(&collinfo[i].dobj);
    5132        1150 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    5133        2300 :         collinfo[i].dobj.namespace =
    5134        1150 :             findNamespace(fout,
    5135        1150 :                           atooid(PQgetvalue(res, i, i_collnamespace)));
    5136        1150 :         collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    5137             : 
    5138             :         /* Decide whether we want to dump it */
    5139        1150 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    5140             : 
    5141             :         /* Collations do not currently have ACLs. */
    5142        1150 :         collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    5143             :     }
    5144             : 
    5145         156 :     PQclear(res);
    5146             : 
    5147         156 :     destroyPQExpBuffer(query);
    5148             : 
    5149         156 :     return collinfo;
    5150             : }
    5151             : 
    5152             : /*
    5153             :  * getConversions:
    5154             :  *    read all conversions in the system catalogs and return them in the
    5155             :  * ConvInfo* structure
    5156             :  *
    5157             :  *  numConversions is set to the number of conversions read in
    5158             :  */
    5159             : ConvInfo *
    5160         156 : getConversions(Archive *fout, int *numConversions)
    5161             : {
    5162             :     PGresult   *res;
    5163             :     int         ntups;
    5164             :     int         i;
    5165             :     PQExpBuffer query;
    5166             :     ConvInfo   *convinfo;
    5167             :     int         i_tableoid;
    5168             :     int         i_oid;
    5169             :     int         i_conname;
    5170             :     int         i_connamespace;
    5171             :     int         i_rolname;
    5172             : 
    5173         156 :     query = createPQExpBuffer();
    5174             : 
    5175             :     /*
    5176             :      * find all conversions, including builtin conversions; we filter out
    5177             :      * system-defined conversions at dump-out time.
    5178             :      */
    5179             : 
    5180         156 :     appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
    5181             :                       "connamespace, "
    5182             :                       "(%s conowner) AS rolname "
    5183             :                       "FROM pg_conversion",
    5184             :                       username_subquery);
    5185             : 
    5186         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5187             : 
    5188         156 :     ntups = PQntuples(res);
    5189         156 :     *numConversions = ntups;
    5190             : 
    5191         156 :     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    5192             : 
    5193         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5194         156 :     i_oid = PQfnumber(res, "oid");
    5195         156 :     i_conname = PQfnumber(res, "conname");
    5196         156 :     i_connamespace = PQfnumber(res, "connamespace");
    5197         156 :     i_rolname = PQfnumber(res, "rolname");
    5198             : 
    5199       20182 :     for (i = 0; i < ntups; i++)
    5200             :     {
    5201       20026 :         convinfo[i].dobj.objType = DO_CONVERSION;
    5202       20026 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5203       20026 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5204       20026 :         AssignDumpId(&convinfo[i].dobj);
    5205       20026 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    5206       40052 :         convinfo[i].dobj.namespace =
    5207       20026 :             findNamespace(fout,
    5208       20026 :                           atooid(PQgetvalue(res, i, i_connamespace)));
    5209       20026 :         convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    5210             : 
    5211             :         /* Decide whether we want to dump it */
    5212       20026 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    5213             : 
    5214             :         /* Conversions do not currently have ACLs. */
    5215       20026 :         convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    5216             :     }
    5217             : 
    5218         156 :     PQclear(res);
    5219             : 
    5220         156 :     destroyPQExpBuffer(query);
    5221             : 
    5222         156 :     return convinfo;
    5223             : }
    5224             : 
    5225             : /*
    5226             :  * getAccessMethods:
    5227             :  *    read all user-defined access methods in the system catalogs and return
    5228             :  *    them in the AccessMethodInfo* structure
    5229             :  *
    5230             :  *  numAccessMethods is set to the number of access methods read in
    5231             :  */
    5232             : AccessMethodInfo *
    5233         156 : getAccessMethods(Archive *fout, int *numAccessMethods)
    5234             : {
    5235             :     PGresult   *res;
    5236             :     int         ntups;
    5237             :     int         i;
    5238             :     PQExpBuffer query;
    5239             :     AccessMethodInfo *aminfo;
    5240             :     int         i_tableoid;
    5241             :     int         i_oid;
    5242             :     int         i_amname;
    5243             :     int         i_amhandler;
    5244             :     int         i_amtype;
    5245             : 
    5246             :     /* Before 9.6, there are no user-defined access methods */
    5247         156 :     if (fout->remoteVersion < 90600)
    5248             :     {
    5249           0 :         *numAccessMethods = 0;
    5250           0 :         return NULL;
    5251             :     }
    5252             : 
    5253         156 :     query = createPQExpBuffer();
    5254             : 
    5255             :     /* Select all access methods from pg_am table */
    5256         156 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
    5257             :                          "amhandler::pg_catalog.regproc AS amhandler "
    5258             :                          "FROM pg_am");
    5259             : 
    5260         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5261             : 
    5262         156 :     ntups = PQntuples(res);
    5263         156 :     *numAccessMethods = ntups;
    5264             : 
    5265         156 :     aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    5266             : 
    5267         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5268         156 :     i_oid = PQfnumber(res, "oid");
    5269         156 :     i_amname = PQfnumber(res, "amname");
    5270         156 :     i_amhandler = PQfnumber(res, "amhandler");
    5271         156 :     i_amtype = PQfnumber(res, "amtype");
    5272             : 
    5273        1402 :     for (i = 0; i < ntups; i++)
    5274             :     {
    5275        1246 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    5276        1246 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5277        1246 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5278        1246 :         AssignDumpId(&aminfo[i].dobj);
    5279        1246 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    5280        1246 :         aminfo[i].dobj.namespace = NULL;
    5281        1246 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    5282        1246 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    5283             : 
    5284             :         /* Decide whether we want to dump it */
    5285        1246 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    5286             : 
    5287             :         /* Access methods do not currently have ACLs. */
    5288        1246 :         aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    5289             :     }
    5290             : 
    5291         156 :     PQclear(res);
    5292             : 
    5293         156 :     destroyPQExpBuffer(query);
    5294             : 
    5295         156 :     return aminfo;
    5296             : }
    5297             : 
    5298             : 
    5299             : /*
    5300             :  * getOpclasses:
    5301             :  *    read all opclasses in the system catalogs and return them in the
    5302             :  * OpclassInfo* structure
    5303             :  *
    5304             :  *  numOpclasses is set to the number of opclasses read in
    5305             :  */
    5306             : OpclassInfo *
    5307         156 : getOpclasses(Archive *fout, int *numOpclasses)
    5308             : {
    5309             :     PGresult   *res;
    5310             :     int         ntups;
    5311             :     int         i;
    5312         156 :     PQExpBuffer query = createPQExpBuffer();
    5313             :     OpclassInfo *opcinfo;
    5314             :     int         i_tableoid;
    5315             :     int         i_oid;
    5316             :     int         i_opcname;
    5317             :     int         i_opcnamespace;
    5318             :     int         i_rolname;
    5319             : 
    5320             :     /*
    5321             :      * find all opclasses, including builtin opclasses; we filter out
    5322             :      * system-defined opclasses at dump-out time.
    5323             :      */
    5324             : 
    5325         156 :     appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
    5326             :                       "opcnamespace, "
    5327             :                       "(%s opcowner) AS rolname "
    5328             :                       "FROM pg_opclass",
    5329             :                       username_subquery);
    5330             : 
    5331         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5332             : 
    5333         156 :     ntups = PQntuples(res);
    5334         156 :     *numOpclasses = ntups;
    5335             : 
    5336         156 :     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    5337             : 
    5338         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5339         156 :     i_oid = PQfnumber(res, "oid");
    5340         156 :     i_opcname = PQfnumber(res, "opcname");
    5341         156 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    5342         156 :     i_rolname = PQfnumber(res, "rolname");
    5343             : 
    5344       20310 :     for (i = 0; i < ntups; i++)
    5345             :     {
    5346       20154 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    5347       20154 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5348       20154 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5349       20154 :         AssignDumpId(&opcinfo[i].dobj);
    5350       20154 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    5351       40308 :         opcinfo[i].dobj.namespace =
    5352       20154 :             findNamespace(fout,
    5353       20154 :                           atooid(PQgetvalue(res, i, i_opcnamespace)));
    5354       20154 :         opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    5355             : 
    5356             :         /* Decide whether we want to dump it */
    5357       20154 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    5358             : 
    5359             :         /* Op Classes do not currently have ACLs. */
    5360       20154 :         opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    5361             : 
    5362       20154 :         if (strlen(opcinfo[i].rolname) == 0)
    5363           0 :             pg_log_warning("owner of operator class \"%s\" appears to be invalid",
    5364             :                            opcinfo[i].dobj.name);
    5365             :     }
    5366             : 
    5367         156 :     PQclear(res);
    5368             : 
    5369         156 :     destroyPQExpBuffer(query);
    5370             : 
    5371         156 :     return opcinfo;
    5372             : }
    5373             : 
    5374             : /*
    5375             :  * getOpfamilies:
    5376             :  *    read all opfamilies in the system catalogs and return them in the
    5377             :  * OpfamilyInfo* structure
    5378             :  *
    5379             :  *  numOpfamilies is set to the number of opfamilies read in
    5380             :  */
    5381             : OpfamilyInfo *
    5382         156 : getOpfamilies(Archive *fout, int *numOpfamilies)
    5383             : {
    5384             :     PGresult   *res;
    5385             :     int         ntups;
    5386             :     int         i;
    5387             :     PQExpBuffer query;
    5388             :     OpfamilyInfo *opfinfo;
    5389             :     int         i_tableoid;
    5390             :     int         i_oid;
    5391             :     int         i_opfname;
    5392             :     int         i_opfnamespace;
    5393             :     int         i_rolname;
    5394             : 
    5395             :     /* Before 8.3, there is no separate concept of opfamilies */
    5396         156 :     if (fout->remoteVersion < 80300)
    5397             :     {
    5398           0 :         *numOpfamilies = 0;
    5399           0 :         return NULL;
    5400             :     }
    5401             : 
    5402         156 :     query = createPQExpBuffer();
    5403             : 
    5404             :     /*
    5405             :      * find all opfamilies, including builtin opfamilies; we filter out
    5406             :      * system-defined opfamilies at dump-out time.
    5407             :      */
    5408             : 
    5409         156 :     appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
    5410             :                       "opfnamespace, "
    5411             :                       "(%s opfowner) AS rolname "
    5412             :                       "FROM pg_opfamily",
    5413             :                       username_subquery);
    5414             : 
    5415         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5416             : 
    5417         156 :     ntups = PQntuples(res);
    5418         156 :     *numOpfamilies = ntups;
    5419             : 
    5420         156 :     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    5421             : 
    5422         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5423         156 :     i_oid = PQfnumber(res, "oid");
    5424         156 :     i_opfname = PQfnumber(res, "opfname");
    5425         156 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    5426         156 :     i_rolname = PQfnumber(res, "rolname");
    5427             : 
    5428       16994 :     for (i = 0; i < ntups; i++)
    5429             :     {
    5430       16838 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    5431       16838 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5432       16838 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5433       16838 :         AssignDumpId(&opfinfo[i].dobj);
    5434       16838 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    5435       33676 :         opfinfo[i].dobj.namespace =
    5436       16838 :             findNamespace(fout,
    5437       16838 :                           atooid(PQgetvalue(res, i, i_opfnamespace)));
    5438       16838 :         opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    5439             : 
    5440             :         /* Decide whether we want to dump it */
    5441       16838 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    5442             : 
    5443             :         /* Extensions do not currently have ACLs. */
    5444       16838 :         opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    5445             : 
    5446       16838 :         if (strlen(opfinfo[i].rolname) == 0)
    5447           0 :             pg_log_warning("owner of operator family \"%s\" appears to be invalid",
    5448             :                            opfinfo[i].dobj.name);
    5449             :     }
    5450             : 
    5451         156 :     PQclear(res);
    5452             : 
    5453         156 :     destroyPQExpBuffer(query);
    5454             : 
    5455         156 :     return opfinfo;
    5456             : }
    5457             : 
    5458             : /*
    5459             :  * getAggregates:
    5460             :  *    read all the user-defined aggregates in the system catalogs and
    5461             :  * return them in the AggInfo* structure
    5462             :  *
    5463             :  * numAggs is set to the number of aggregates read in
    5464             :  */
    5465             : AggInfo *
    5466         156 : getAggregates(Archive *fout, int *numAggs)
    5467             : {
    5468         156 :     DumpOptions *dopt = fout->dopt;
    5469             :     PGresult   *res;
    5470             :     int         ntups;
    5471             :     int         i;
    5472         156 :     PQExpBuffer query = createPQExpBuffer();
    5473             :     AggInfo    *agginfo;
    5474             :     int         i_tableoid;
    5475             :     int         i_oid;
    5476             :     int         i_aggname;
    5477             :     int         i_aggnamespace;
    5478             :     int         i_pronargs;
    5479             :     int         i_proargtypes;
    5480             :     int         i_rolname;
    5481             :     int         i_aggacl;
    5482             :     int         i_raggacl;
    5483             :     int         i_initaggacl;
    5484             :     int         i_initraggacl;
    5485             : 
    5486             :     /*
    5487             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    5488             :      * rationale behind the filtering logic.
    5489             :      */
    5490         156 :     if (fout->remoteVersion >= 90600)
    5491             :     {
    5492         156 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    5493         156 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    5494         156 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    5495         156 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    5496             :         const char *agg_check;
    5497             : 
    5498         156 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    5499             :                         initracl_subquery, "p.proacl", "p.proowner", "'f'",
    5500         156 :                         dopt->binary_upgrade);
    5501             : 
    5502         312 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    5503         156 :                      : "p.proisagg");
    5504             : 
    5505         156 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    5506             :                           "p.proname AS aggname, "
    5507             :                           "p.pronamespace AS aggnamespace, "
    5508             :                           "p.pronargs, p.proargtypes, "
    5509             :                           "(%s p.proowner) AS rolname, "
    5510             :                           "%s AS aggacl, "
    5511             :                           "%s AS raggacl, "
    5512             :                           "%s AS initaggacl, "
    5513             :                           "%s AS initraggacl "
    5514             :                           "FROM pg_proc p "
    5515             :                           "LEFT JOIN pg_init_privs pip ON "
    5516             :                           "(p.oid = pip.objoid "
    5517             :                           "AND pip.classoid = 'pg_proc'::regclass "
    5518             :                           "AND pip.objsubid = 0) "
    5519             :                           "WHERE %s AND ("
    5520             :                           "p.pronamespace != "
    5521             :                           "(SELECT oid FROM pg_namespace "
    5522             :                           "WHERE nspname = 'pg_catalog') OR "
    5523             :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    5524             :                           username_subquery,
    5525             :                           acl_subquery->data,
    5526             :                           racl_subquery->data,
    5527             :                           initacl_subquery->data,
    5528             :                           initracl_subquery->data,
    5529             :                           agg_check);
    5530         156 :         if (dopt->binary_upgrade)
    5531          16 :             appendPQExpBufferStr(query,
    5532             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    5533             :                                  "classid = 'pg_proc'::regclass AND "
    5534             :                                  "objid = p.oid AND "
    5535             :                                  "refclassid = 'pg_extension'::regclass AND "
    5536             :                                  "deptype = 'e')");
    5537         156 :         appendPQExpBufferChar(query, ')');
    5538             : 
    5539         156 :         destroyPQExpBuffer(acl_subquery);
    5540         156 :         destroyPQExpBuffer(racl_subquery);
    5541         156 :         destroyPQExpBuffer(initacl_subquery);
    5542         156 :         destroyPQExpBuffer(initracl_subquery);
    5543             :     }
    5544           0 :     else if (fout->remoteVersion >= 80200)
    5545             :     {
    5546           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
    5547             :                           "pronamespace AS aggnamespace, "
    5548             :                           "pronargs, proargtypes, "
    5549             :                           "(%s proowner) AS rolname, "
    5550             :                           "proacl AS aggacl, "
    5551             :                           "NULL AS raggacl, "
    5552             :                           "NULL AS initaggacl, NULL AS initraggacl "
    5553             :                           "FROM pg_proc p "
    5554             :                           "WHERE proisagg AND ("
    5555             :                           "pronamespace != "
    5556             :                           "(SELECT oid FROM pg_namespace "
    5557             :                           "WHERE nspname = 'pg_catalog')",
    5558             :                           username_subquery);
    5559           0 :         if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
    5560           0 :             appendPQExpBufferStr(query,
    5561             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    5562             :                                  "classid = 'pg_proc'::regclass AND "
    5563             :                                  "objid = p.oid AND "
    5564             :                                  "refclassid = 'pg_extension'::regclass AND "
    5565             :                                  "deptype = 'e')");
    5566           0 :         appendPQExpBufferChar(query, ')');
    5567             :     }
    5568             :     else
    5569             :     {
    5570           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
    5571             :                           "pronamespace AS aggnamespace, "
    5572             :                           "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
    5573             :                           "proargtypes, "
    5574             :                           "(%s proowner) AS rolname, "
    5575             :                           "proacl AS aggacl, "
    5576             :                           "NULL AS raggacl, "
    5577             :                           "NULL AS initaggacl, NULL AS initraggacl "
    5578             :                           "FROM pg_proc "
    5579             :                           "WHERE proisagg "
    5580             :                           "AND pronamespace != "
    5581             :                           "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
    5582             :                           username_subquery);
    5583             :     }
    5584             : 
    5585         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5586             : 
    5587         156 :     ntups = PQntuples(res);
    5588         156 :     *numAggs = ntups;
    5589             : 
    5590         156 :     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    5591             : 
    5592         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5593         156 :     i_oid = PQfnumber(res, "oid");
    5594         156 :     i_aggname = PQfnumber(res, "aggname");
    5595         156 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    5596         156 :     i_pronargs = PQfnumber(res, "pronargs");
    5597         156 :     i_proargtypes = PQfnumber(res, "proargtypes");
    5598         156 :     i_rolname = PQfnumber(res, "rolname");
    5599         156 :     i_aggacl = PQfnumber(res, "aggacl");
    5600         156 :     i_raggacl = PQfnumber(res, "raggacl");
    5601         156 :     i_initaggacl = PQfnumber(res, "initaggacl");
    5602         156 :     i_initraggacl = PQfnumber(res, "initraggacl");
    5603             : 
    5604         522 :     for (i = 0; i < ntups; i++)
    5605             :     {
    5606         366 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    5607         366 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5608         366 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5609         366 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    5610         366 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    5611         732 :         agginfo[i].aggfn.dobj.namespace =
    5612         366 :             findNamespace(fout,
    5613         366 :                           atooid(PQgetvalue(res, i, i_aggnamespace)));
    5614         366 :         agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    5615         366 :         if (strlen(agginfo[i].aggfn.rolname) == 0)
    5616           0 :             pg_log_warning("owner of aggregate function \"%s\" appears to be invalid",
    5617             :                            agginfo[i].aggfn.dobj.name);
    5618         366 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    5619         366 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    5620         366 :         agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    5621         366 :         agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
    5622         366 :         agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
    5623         366 :         agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
    5624         366 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    5625         366 :         if (agginfo[i].aggfn.nargs == 0)
    5626          48 :             agginfo[i].aggfn.argtypes = NULL;
    5627             :         else
    5628             :         {
    5629         318 :             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    5630         636 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    5631         318 :                           agginfo[i].aggfn.argtypes,
    5632         318 :                           agginfo[i].aggfn.nargs);
    5633             :         }
    5634             : 
    5635             :         /* Decide whether we want to dump it */
    5636         366 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    5637             : 
    5638             :         /* Do not try to dump ACL if no ACL exists. */
    5639         732 :         if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
    5640         730 :             PQgetisnull(res, i, i_initaggacl) &&
    5641         364 :             PQgetisnull(res, i, i_initraggacl))
    5642         364 :             agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
    5643             :     }
    5644             : 
    5645         156 :     PQclear(res);
    5646             : 
    5647         156 :     destroyPQExpBuffer(query);
    5648             : 
    5649         156 :     return agginfo;
    5650             : }
    5651             : 
    5652             : /*
    5653             :  * getFuncs:
    5654             :  *    read all the user-defined functions in the system catalogs and
    5655             :  * return them in the FuncInfo* structure
    5656             :  *
    5657             :  * numFuncs is set to the number of functions read in
    5658             :  */
    5659             : FuncInfo *
    5660         156 : getFuncs(Archive *fout, int *numFuncs)
    5661             : {
    5662         156 :     DumpOptions *dopt = fout->dopt;
    5663             :     PGresult   *res;
    5664             :     int         ntups;
    5665             :     int         i;
    5666         156 :     PQExpBuffer query = createPQExpBuffer();
    5667             :     FuncInfo   *finfo;
    5668             :     int         i_tableoid;
    5669             :     int         i_oid;
    5670             :     int         i_proname;
    5671             :     int         i_pronamespace;
    5672             :     int         i_rolname;
    5673             :     int         i_prolang;
    5674             :     int         i_pronargs;
    5675             :     int         i_proargtypes;
    5676             :     int         i_prorettype;
    5677             :     int         i_proacl;
    5678             :     int         i_rproacl;
    5679             :     int         i_initproacl;
    5680             :     int         i_initrproacl;
    5681             : 
    5682             :     /*
    5683             :      * Find all interesting functions.  This is a bit complicated:
    5684             :      *
    5685             :      * 1. Always exclude aggregates; those are handled elsewhere.
    5686             :      *
    5687             :      * 2. Always exclude functions that are internally dependent on something
    5688             :      * else, since presumably those will be created as a result of creating
    5689             :      * the something else.  This currently acts only to suppress constructor
    5690             :      * functions for range types (so we only need it in 9.2 and up).  Note
    5691             :      * this is OK only because the constructors don't have any dependencies
    5692             :      * the range type doesn't have; otherwise we might not get creation
    5693             :      * ordering correct.
    5694             :      *
    5695             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    5696             :      * they're members of extensions and we are in binary-upgrade mode then
    5697             :      * include them, since we want to dump extension members individually in
    5698             :      * that mode.  Also, if they are used by casts or transforms then we need
    5699             :      * to gather the information about them, though they won't be dumped if
    5700             :      * they are built-in.  Also, in 9.6 and up, include functions in
    5701             :      * pg_catalog if they have an ACL different from what's shown in
    5702             :      * pg_init_privs.
    5703             :      */
    5704         156 :     if (fout->remoteVersion >= 90600)
    5705             :     {
    5706         156 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    5707         156 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    5708         156 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    5709         156 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    5710             :         const char *not_agg_check;
    5711             : 
    5712         156 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    5713             :                         initracl_subquery, "p.proacl", "p.proowner", "'f'",
    5714         156 :                         dopt->binary_upgrade);
    5715             : 
    5716         312 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    5717         156 :                          : "NOT p.proisagg");
    5718             : 
    5719         156 :         appendPQExpBuffer(query,
    5720             :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    5721             :                           "p.pronargs, p.proargtypes, p.prorettype, "
    5722             :                           "%s AS proacl, "
    5723             :                           "%s AS rproacl, "
    5724             :                           "%s AS initproacl, "
    5725             :                           "%s AS initrproacl, "
    5726             :                           "p.pronamespace, "
    5727             :                           "(%s p.proowner) AS rolname "
    5728             :                           "FROM pg_proc p "
    5729             :                           "LEFT JOIN pg_init_privs pip ON "
    5730             :                           "(p.oid = pip.objoid "
    5731             :                           "AND pip.classoid = 'pg_proc'::regclass "
    5732             :                           "AND pip.objsubid = 0) "
    5733             :                           "WHERE %s"
    5734             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    5735             :                           "WHERE classid = 'pg_proc'::regclass AND "
    5736             :                           "objid = p.oid AND deptype = 'i')"
    5737             :                           "\n  AND ("
    5738             :                           "\n  pronamespace != "
    5739             :                           "(SELECT oid FROM pg_namespace "
    5740             :                           "WHERE nspname = 'pg_catalog')"
    5741             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    5742             :                           "\n  WHERE pg_cast.oid > %u "
    5743             :                           "\n  AND p.oid = pg_cast.castfunc)"
    5744             :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    5745             :                           "\n  WHERE pg_transform.oid > %u AND "
    5746             :                           "\n  (p.oid = pg_transform.trffromsql"
    5747             :                           "\n  OR p.oid = pg_transform.trftosql))",
    5748             :                           acl_subquery->data,
    5749             :                           racl_subquery->data,
    5750             :                           initacl_subquery->data,
    5751             :                           initracl_subquery->data,
    5752             :                           username_subquery,
    5753             :                           not_agg_check,
    5754             :                           g_last_builtin_oid,
    5755             :                           g_last_builtin_oid);
    5756         156 :         if (dopt->binary_upgrade)
    5757          16 :             appendPQExpBufferStr(query,
    5758             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    5759             :                                  "classid = 'pg_proc'::regclass AND "
    5760             :                                  "objid = p.oid AND "
    5761             :                                  "refclassid = 'pg_extension'::regclass AND "
    5762             :                                  "deptype = 'e')");
    5763         156 :         appendPQExpBufferStr(query,
    5764             :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    5765         156 :         appendPQExpBufferChar(query, ')');
    5766             : 
    5767         156 :         destroyPQExpBuffer(acl_subquery);
    5768         156 :         destroyPQExpBuffer(racl_subquery);
    5769         156 :         destroyPQExpBuffer(initacl_subquery);
    5770         156 :         destroyPQExpBuffer(initracl_subquery);
    5771             :     }
    5772             :     else
    5773             :     {
    5774           0 :         appendPQExpBuffer(query,
    5775             :                           "SELECT tableoid, oid, proname, prolang, "
    5776             :                           "pronargs, proargtypes, prorettype, proacl, "
    5777             :                           "NULL as rproacl, "
    5778             :                           "NULL as initproacl, NULL AS initrproacl, "
    5779             :                           "pronamespace, "
    5780             :                           "(%s proowner) AS rolname "
    5781             :                           "FROM pg_proc p "
    5782             :                           "WHERE NOT proisagg",
    5783             :                           username_subquery);
    5784           0 :         if (fout->remoteVersion >= 90200)
    5785           0 :             appendPQExpBufferStr(query,
    5786             :                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    5787             :                                  "WHERE classid = 'pg_proc'::regclass AND "
    5788             :                                  "objid = p.oid AND deptype = 'i')");
    5789           0 :         appendPQExpBuffer(query,
    5790             :                           "\n  AND ("
    5791             :                           "\n  pronamespace != "
    5792             :                           "(SELECT oid FROM pg_namespace "
    5793             :                           "WHERE nspname = 'pg_catalog')"
    5794             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    5795             :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    5796             :                           "\n  AND p.oid = pg_cast.castfunc)",
    5797             :                           g_last_builtin_oid);
    5798             : 
    5799           0 :         if (fout->remoteVersion >= 90500)
    5800           0 :             appendPQExpBuffer(query,
    5801             :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    5802             :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    5803             :                               "\n  AND (p.oid = pg_transform.trffromsql"
    5804             :                               "\n  OR p.oid = pg_transform.trftosql))",
    5805             :                               g_last_builtin_oid);
    5806             : 
    5807           0 :         if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
    5808           0 :             appendPQExpBufferStr(query,
    5809             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    5810             :                                  "classid = 'pg_proc'::regclass AND "
    5811             :                                  "objid = p.oid AND "
    5812             :                                  "refclassid = 'pg_extension'::regclass AND "
    5813             :                                  "deptype = 'e')");
    5814           0 :         appendPQExpBufferChar(query, ')');
    5815             :     }
    5816             : 
    5817         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5818             : 
    5819         156 :     ntups = PQntuples(res);
    5820             : 
    5821         156 :     *numFuncs = ntups;
    5822             : 
    5823         156 :     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    5824             : 
    5825         156 :     i_tableoid = PQfnumber(res, "tableoid");
    5826         156 :     i_oid = PQfnumber(res, "oid");
    5827         156 :     i_proname = PQfnumber(res, "proname");
    5828         156 :     i_pronamespace = PQfnumber(res, "pronamespace");
    5829         156 :     i_rolname = PQfnumber(res, "rolname");
    5830         156 :     i_prolang = PQfnumber(res, "prolang");
    5831         156 :     i_pronargs = PQfnumber(res, "pronargs");
    5832         156 :     i_proargtypes = PQfnumber(res, "proargtypes");
    5833         156 :     i_prorettype = PQfnumber(res, "prorettype");
    5834         156 :     i_proacl = PQfnumber(res, "proacl");
    5835         156 :     i_rproacl = PQfnumber(res, "rproacl");
    5836         156 :     i_initproacl = PQfnumber(res, "initproacl");
    5837         156 :     i_initrproacl = PQfnumber(res, "initrproacl");
    5838             : 
    5839        3928 :     for (i = 0; i < ntups; i++)
    5840             :     {
    5841        3772 :         finfo[i].dobj.objType = DO_FUNC;
    5842        3772 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5843        3772 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5844        3772 :         AssignDumpId(&finfo[i].dobj);
    5845        3772 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    5846        7544 :         finfo[i].dobj.namespace =
    5847        3772 :             findNamespace(fout,
    5848        3772 :                           atooid(PQgetvalue(res, i, i_pronamespace)));
    5849        3772 :         finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    5850        3772 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    5851        3772 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    5852        3772 :         finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
    5853        3772 :         finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
    5854        3772 :         finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
    5855        3772 :         finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
    5856        3772 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    5857        3772 :         if (finfo[i].nargs == 0)
    5858         778 :             finfo[i].argtypes = NULL;
    5859             :         else
    5860             :         {
    5861        2994 :             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    5862        5988 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    5863        5988 :                           finfo[i].argtypes, finfo[i].nargs);
    5864             :         }
    5865             : 
    5866             :         /* Decide whether we want to dump it */
    5867        3772 :         selectDumpableObject(&(finfo[i].dobj), fout);
    5868             : 
    5869             :         /* Do not try to dump ACL if no ACL exists. */
    5870        7486 :         if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
    5871        7426 :             PQgetisnull(res, i, i_initproacl) &&
    5872        3712 :             PQgetisnull(res, i, i_initrproacl))
    5873        3712 :             finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    5874             : 
    5875        3772 :         if (strlen(finfo[i].rolname) == 0)
    5876           0 :             pg_log_warning("owner of function \"%s\" appears to be invalid",
    5877             :                            finfo[i].dobj.name);
    5878             :     }
    5879             : 
    5880         156 :     PQclear(res);
    5881             : 
    5882         156 :     destroyPQExpBuffer(query);
    5883             : 
    5884         156 :     return finfo;
    5885             : }
    5886             : 
    5887             : /*
    5888             :  * getTables
    5889             :  *    read all the tables (no indexes)
    5890             :  * in the system catalogs return them in the TableInfo* structure
    5891             :  *
    5892             :  * numTables is set to the number of tables read in
    5893             :  */
    5894             : TableInfo *
    5895         158 : getTables(Archive *fout, int *numTables)
    5896             : {
    5897         158 :     DumpOptions *dopt = fout->dopt;
    5898             :     PGresult   *res;
    5899             :     int         ntups;
    5900             :     int         i;
    5901         158 :     PQExpBuffer query = createPQExpBuffer();
    5902             :     TableInfo  *tblinfo;
    5903             :     int         i_reltableoid;
    5904             :     int         i_reloid;
    5905             :     int         i_relname;
    5906             :     int         i_relnamespace;
    5907             :     int         i_relkind;
    5908             :     int         i_relacl;
    5909             :     int         i_rrelacl;
    5910             :     int         i_initrelacl;
    5911             :     int         i_initrrelacl;
    5912             :     int         i_rolname;
    5913             :     int         i_relchecks;
    5914             :     int         i_relhastriggers;
    5915             :     int         i_relhasindex;
    5916             :     int         i_relhasrules;
    5917             :     int         i_relrowsec;
    5918             :     int         i_relforcerowsec;
    5919             :     int         i_relhasoids;
    5920             :     int         i_relfrozenxid;
    5921             :     int         i_relminmxid;
    5922             :     int         i_toastoid;
    5923             :     int         i_toastfrozenxid;
    5924             :     int         i_toastminmxid;
    5925             :     int         i_relpersistence;
    5926             :     int         i_relispopulated;
    5927             :     int         i_relreplident;
    5928             :     int         i_owning_tab;
    5929             :     int         i_owning_col;
    5930             :     int         i_reltablespace;
    5931             :     int         i_reloptions;
    5932             :     int         i_checkoption;
    5933             :     int         i_toastreloptions;
    5934             :     int         i_reloftype;
    5935             :     int         i_relpages;
    5936             :     int         i_is_identity_sequence;
    5937             :     int         i_changed_acl;
    5938             :     int         i_partkeydef;
    5939             :     int         i_ispartition;
    5940             :     int         i_partbound;
    5941             :     int         i_amname;
    5942             : 
    5943             :     /*
    5944             :      * Find all the tables and table-like objects.
    5945             :      *
    5946             :      * We include system catalogs, so that we can work if a user table is
    5947             :      * defined to inherit from a system catalog (pretty weird, but...)
    5948             :      *
    5949             :      * We ignore relations that are not ordinary tables, sequences, views,
    5950             :      * materialized views, composite types, or foreign tables.
    5951             :      *
    5952             :      * Composite-type table entries won't be dumped as such, but we have to
    5953             :      * make a DumpableObject for them so that we can track dependencies of the
    5954             :      * composite type (pg_depend entries for columns of the composite type
    5955             :      * link to the pg_class entry not the pg_type entry).
    5956             :      *
    5957             :      * Note: in this phase we should collect only a minimal amount of
    5958             :      * information about each table, basically just enough to decide if it is
    5959             :      * interesting. We must fetch all tables in this phase because otherwise
    5960             :      * we cannot correctly identify inherited columns, owned sequences, etc.
    5961             :      *
    5962             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    5963             :      * that versions 10 and 11 have them, but 12 does not, so emitting them
    5964             :      * causes the upgrade to fail.
    5965             :      */
    5966             : 
    5967         158 :     if (fout->remoteVersion >= 90600)
    5968             :     {
    5969         158 :         char       *partkeydef = "NULL";
    5970         158 :         char       *ispartition = "false";
    5971         158 :         char       *partbound = "NULL";
    5972         158 :         char       *relhasoids = "c.relhasoids";
    5973             : 
    5974         158 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    5975         158 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    5976         158 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    5977         158 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    5978             : 
    5979         158 :         PQExpBuffer attacl_subquery = createPQExpBuffer();
    5980         158 :         PQExpBuffer attracl_subquery = createPQExpBuffer();
    5981         158 :         PQExpBuffer attinitacl_subquery = createPQExpBuffer();
    5982         158 :         PQExpBuffer attinitracl_subquery = createPQExpBuffer();
    5983             : 
    5984             :         /*
    5985             :          * Collect the information about any partitioned tables, which were
    5986             :          * added in PG10.
    5987             :          */
    5988             : 
    5989         158 :         if (fout->remoteVersion >= 100000)
    5990             :         {
    5991         158 :             partkeydef = "pg_get_partkeydef(c.oid)";
    5992         158 :             ispartition = "c.relispartition";
    5993         158 :             partbound = "pg_get_expr(c.relpartbound, c.oid)";
    5994             :         }
    5995             : 
    5996             :         /* In PG12 upwards WITH OIDS does not exist anymore. */
    5997         158 :         if (fout->remoteVersion >= 120000)
    5998         158 :             relhasoids = "'f'::bool";
    5999             : 
    6000             :         /*
    6001             :          * Left join to pick up dependency info linking sequences to their
    6002             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6003             :          *
    6004             :          * Left join to detect if any privileges are still as-set-at-init, in
    6005             :          * which case we won't dump out ACL commands for those.
    6006             :          */
    6007             : 
    6008         158 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    6009             :                         initracl_subquery, "c.relacl", "c.relowner",
    6010             :                         "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    6011             :                         " THEN 's' ELSE 'r' END::\"char\"",
    6012         158 :                         dopt->binary_upgrade);
    6013             : 
    6014         158 :         buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
    6015             :                         attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
    6016         158 :                         dopt->binary_upgrade);
    6017             : 
    6018         158 :         appendPQExpBuffer(query,
    6019             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6020             :                           "%s AS relacl, %s as rrelacl, "
    6021             :                           "%s AS initrelacl, %s as initrrelacl, "
    6022             :                           "c.relkind, c.relnamespace, "
    6023             :                           "(%s c.relowner) AS rolname, "
    6024             :                           "c.relchecks, c.relhastriggers, "
    6025             :                           "c.relhasindex, c.relhasrules, %s AS relhasoids, "
    6026             :                           "c.relrowsecurity, c.relforcerowsecurity, "
    6027             :                           "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
    6028             :                           "tc.relfrozenxid AS tfrozenxid, "
    6029             :                           "tc.relminmxid AS tminmxid, "
    6030             :                           "c.relpersistence, c.relispopulated, "
    6031             :                           "c.relreplident, c.relpages, am.amname, "
    6032             :                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
    6033             :                           "d.refobjid AS owning_tab, "
    6034             :                           "d.refobjsubid AS owning_col, "
    6035             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6036             :                           "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    6037             :                           "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    6038             :                           "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
    6039             :                           "tc.reloptions AS toast_reloptions, "
    6040             :                           "c.relkind = '%c' AND EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_class'::regclass AND objid = c.oid AND objsubid = 0 AND refclassid = 'pg_class'::regclass AND deptype = 'i') AS is_identity_sequence, "
    6041             :                           "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
    6042             :                           "(c.oid = pip.objoid "
    6043             :                           "AND pip.classoid = 'pg_class'::regclass "
    6044             :                           "AND pip.objsubid = at.attnum)"
    6045             :                           "WHERE at.attrelid = c.oid AND ("
    6046             :                           "%s IS NOT NULL "
    6047             :                           "OR %s IS NOT NULL "
    6048             :                           "OR %s IS NOT NULL "
    6049             :                           "OR %s IS NOT NULL"
    6050             :                           "))"
    6051             :                           "AS changed_acl, "
    6052             :                           "%s AS partkeydef, "
    6053             :                           "%s AS ispartition, "
    6054             :                           "%s AS partbound "
    6055             :                           "FROM pg_class c "
    6056             :                           "LEFT JOIN pg_depend d ON "
    6057             :                           "(c.relkind = '%c' AND "
    6058             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6059             :                           "d.objsubid = 0 AND "
    6060             :                           "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
    6061             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> '%c') "
    6062             :                           "LEFT JOIN pg_am am ON (c.relam = am.oid) "
    6063             :                           "LEFT JOIN pg_init_privs pip ON "
    6064             :                           "(c.oid = pip.objoid "
    6065             :                           "AND pip.classoid = 'pg_class'::regclass "
    6066             :                           "AND pip.objsubid = 0) "
    6067             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
    6068             :                           "ORDER BY c.oid",
    6069             :                           acl_subquery->data,
    6070             :                           racl_subquery->data,
    6071             :                           initacl_subquery->data,
    6072             :                           initracl_subquery->data,
    6073             :                           username_subquery,
    6074             :                           relhasoids,
    6075             :                           RELKIND_SEQUENCE,
    6076             :                           attacl_subquery->data,
    6077             :                           attracl_subquery->data,
    6078             :                           attinitacl_subquery->data,
    6079             :                           attinitracl_subquery->data,
    6080             :                           partkeydef,
    6081             :                           ispartition,
    6082             :                           partbound,
    6083             :                           RELKIND_SEQUENCE,
    6084             :                           RELKIND_PARTITIONED_TABLE,
    6085             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6086             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
    6087             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    6088             :                           RELKIND_PARTITIONED_TABLE);
    6089             : 
    6090         158 :         destroyPQExpBuffer(acl_subquery);
    6091         158 :         destroyPQExpBuffer(racl_subquery);
    6092         158 :         destroyPQExpBuffer(initacl_subquery);
    6093         158 :         destroyPQExpBuffer(initracl_subquery);
    6094             : 
    6095         158 :         destroyPQExpBuffer(attacl_subquery);
    6096         158 :         destroyPQExpBuffer(attracl_subquery);
    6097         158 :         destroyPQExpBuffer(attinitacl_subquery);
    6098         158 :         destroyPQExpBuffer(attinitracl_subquery);
    6099             :     }
    6100           0 :     else if (fout->remoteVersion >= 90500)
    6101             :     {
    6102             :         /*
    6103             :          * Left join to pick up dependency info linking sequences to their
    6104             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6105             :          */
    6106           0 :         appendPQExpBuffer(query,
    6107             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6108             :                           "c.relacl, NULL as rrelacl, "
    6109             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6110             :                           "c.relkind, "
    6111             :                           "c.relnamespace, "
    6112             :                           "(%s c.relowner) AS rolname, "
    6113             :                           "c.relchecks, c.relhastriggers, "
    6114             :                           "c.relhasindex, c.relhasrules, c.relhasoids, "
    6115             :                           "c.relrowsecurity, c.relforcerowsecurity, "
    6116             :                           "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
    6117             :                           "tc.relfrozenxid AS tfrozenxid, "
    6118             :                           "tc.relminmxid AS tminmxid, "
    6119             :                           "c.relpersistence, c.relispopulated, "
    6120             :                           "c.relreplident, c.relpages, "
    6121             :                           "NULL AS amname, "
    6122             :                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
    6123             :                           "d.refobjid AS owning_tab, "
    6124             :                           "d.refobjsubid AS owning_col, "
    6125             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6126             :                           "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    6127             :                           "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    6128             :                           "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
    6129             :                           "tc.reloptions AS toast_reloptions, "
    6130             :                           "NULL AS changed_acl, "
    6131             :                           "NULL AS partkeydef, "
    6132             :                           "false AS ispartition, "
    6133             :                           "NULL AS partbound "
    6134             :                           "FROM pg_class c "
    6135             :                           "LEFT JOIN pg_depend d ON "
    6136             :                           "(c.relkind = '%c' AND "
    6137             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6138             :                           "d.objsubid = 0 AND "
    6139             :                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
    6140             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
    6141             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
    6142             :                           "ORDER BY c.oid",
    6143             :                           username_subquery,
    6144             :                           RELKIND_SEQUENCE,
    6145             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6146             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
    6147             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
    6148             :     }
    6149           0 :     else if (fout->remoteVersion >= 90400)
    6150             :     {
    6151             :         /*
    6152             :          * Left join to pick up dependency info linking sequences to their
    6153             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6154             :          */
    6155           0 :         appendPQExpBuffer(query,
    6156             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6157             :                           "c.relacl, NULL as rrelacl, "
    6158             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6159             :                           "c.relkind, "
    6160             :                           "c.relnamespace, "
    6161             :                           "(%s c.relowner) AS rolname, "
    6162             :                           "c.relchecks, c.relhastriggers, "
    6163             :                           "c.relhasindex, c.relhasrules, c.relhasoids, "
    6164             :                           "'f'::bool AS relrowsecurity, "
    6165             :                           "'f'::bool AS relforcerowsecurity, "
    6166             :                           "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
    6167             :                           "tc.relfrozenxid AS tfrozenxid, "
    6168             :                           "tc.relminmxid AS tminmxid, "
    6169             :                           "c.relpersistence, c.relispopulated, "
    6170             :                           "c.relreplident, c.relpages, "
    6171             :                           "NULL AS amname, "
    6172             :                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
    6173             :                           "d.refobjid AS owning_tab, "
    6174             :                           "d.refobjsubid AS owning_col, "
    6175             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6176             :                           "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    6177             :                           "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    6178             :                           "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
    6179             :                           "tc.reloptions AS toast_reloptions, "
    6180             :                           "NULL AS changed_acl, "
    6181             :                           "NULL AS partkeydef, "
    6182             :                           "false AS ispartition, "
    6183             :                           "NULL AS partbound "
    6184             :                           "FROM pg_class c "
    6185             :                           "LEFT JOIN pg_depend d ON "
    6186             :                           "(c.relkind = '%c' AND "
    6187             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6188             :                           "d.objsubid = 0 AND "
    6189             :                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
    6190             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
    6191             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
    6192             :                           "ORDER BY c.oid",
    6193             :                           username_subquery,
    6194             :                           RELKIND_SEQUENCE,
    6195             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6196             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
    6197             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
    6198             :     }
    6199           0 :     else if (fout->remoteVersion >= 90300)
    6200             :     {
    6201             :         /*
    6202             :          * Left join to pick up dependency info linking sequences to their
    6203             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6204             :          */
    6205           0 :         appendPQExpBuffer(query,
    6206             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6207             :                           "c.relacl, NULL as rrelacl, "
    6208             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6209             :                           "c.relkind, "
    6210             :                           "c.relnamespace, "
    6211             :                           "(%s c.relowner) AS rolname, "
    6212             :                           "c.relchecks, c.relhastriggers, "
    6213             :                           "c.relhasindex, c.relhasrules, c.relhasoids, "
    6214             :                           "'f'::bool AS relrowsecurity, "
    6215             :                           "'f'::bool AS relforcerowsecurity, "
    6216             :                           "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
    6217             :                           "tc.relfrozenxid AS tfrozenxid, "
    6218             :                           "tc.relminmxid AS tminmxid, "
    6219             :                           "c.relpersistence, c.relispopulated, "
    6220             :                           "'d' AS relreplident, c.relpages, "
    6221             :                           "NULL AS amname, "
    6222             :                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
    6223             :                           "d.refobjid AS owning_tab, "
    6224             :                           "d.refobjsubid AS owning_col, "
    6225             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6226             :                           "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    6227             :                           "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    6228             :                           "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
    6229             :                           "tc.reloptions AS toast_reloptions, "
    6230             :                           "NULL AS changed_acl, "
    6231             :                           "NULL AS partkeydef, "
    6232             :                           "false AS ispartition, "
    6233             :                           "NULL AS partbound "
    6234             :                           "FROM pg_class c "
    6235             :                           "LEFT JOIN pg_depend d ON "
    6236             :                           "(c.relkind = '%c' AND "
    6237             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6238             :                           "d.objsubid = 0 AND "
    6239             :                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
    6240             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
    6241             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
    6242             :                           "ORDER BY c.oid",
    6243             :                           username_subquery,
    6244             :                           RELKIND_SEQUENCE,
    6245             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6246             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
    6247             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
    6248             :     }
    6249           0 :     else if (fout->remoteVersion >= 90100)
    6250             :     {
    6251             :         /*
    6252             :          * Left join to pick up dependency info linking sequences to their
    6253             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6254             :          */
    6255           0 :         appendPQExpBuffer(query,
    6256             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6257             :                           "c.relacl, NULL as rrelacl, "
    6258             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6259             :                           "c.relkind, "
    6260             :                           "c.relnamespace, "
    6261             :                           "(%s c.relowner) AS rolname, "
    6262             :                           "c.relchecks, c.relhastriggers, "
    6263             :                           "c.relhasindex, c.relhasrules, c.relhasoids, "
    6264             :                           "'f'::bool AS relrowsecurity, "
    6265             :                           "'f'::bool AS relforcerowsecurity, "
    6266             :                           "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
    6267             :                           "tc.relfrozenxid AS tfrozenxid, "
    6268             :                           "0 AS tminmxid, "
    6269             :                           "c.relpersistence, 't' as relispopulated, "
    6270             :                           "'d' AS relreplident, c.relpages, "
    6271             :                           "NULL AS amname, "
    6272             :                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
    6273             :                           "d.refobjid AS owning_tab, "
    6274             :                           "d.refobjsubid AS owning_col, "
    6275             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6276             :                           "c.reloptions AS reloptions, "
    6277             :                           "tc.reloptions AS toast_reloptions, "
    6278             :                           "NULL AS changed_acl, "
    6279             :                           "NULL AS partkeydef, "
    6280             :                           "false AS ispartition, "
    6281             :                           "NULL AS partbound "
    6282             :                           "FROM pg_class c "
    6283             :                           "LEFT JOIN pg_depend d ON "
    6284             :                           "(c.relkind = '%c' AND "
    6285             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6286             :                           "d.objsubid = 0 AND "
    6287             :                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
    6288             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
    6289             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
    6290             :                           "ORDER BY c.oid",
    6291             :                           username_subquery,
    6292             :                           RELKIND_SEQUENCE,
    6293             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6294             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
    6295             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
    6296             :     }
    6297           0 :     else if (fout->remoteVersion >= 90000)
    6298             :     {
    6299             :         /*
    6300             :          * Left join to pick up dependency info linking sequences to their
    6301             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6302             :          */
    6303           0 :         appendPQExpBuffer(query,
    6304             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6305             :                           "c.relacl, NULL as rrelacl, "
    6306             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6307             :                           "c.relkind, "
    6308             :                           "c.relnamespace, "
    6309             :                           "(%s c.relowner) AS rolname, "
    6310             :                           "c.relchecks, c.relhastriggers, "
    6311             :                           "c.relhasindex, c.relhasrules, c.relhasoids, "
    6312             :                           "'f'::bool AS relrowsecurity, "
    6313             :                           "'f'::bool AS relforcerowsecurity, "
    6314             :                           "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
    6315             :                           "tc.relfrozenxid AS tfrozenxid, "
    6316             :                           "0 AS tminmxid, "
    6317             :                           "'p' AS relpersistence, 't' as relispopulated, "
    6318             :                           "'d' AS relreplident, c.relpages, "
    6319             :                           "NULL AS amname, "
    6320             :                           "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
    6321             :                           "d.refobjid AS owning_tab, "
    6322             :                           "d.refobjsubid AS owning_col, "
    6323             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6324             :                           "c.reloptions AS reloptions, "
    6325             :                           "tc.reloptions AS toast_reloptions, "
    6326             :                           "NULL AS changed_acl, "
    6327             :                           "NULL AS partkeydef, "
    6328             :                           "false AS ispartition, "
    6329             :                           "NULL AS partbound "
    6330             :                           "FROM pg_class c "
    6331             :                           "LEFT JOIN pg_depend d ON "
    6332             :                           "(c.relkind = '%c' AND "
    6333             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6334             :                           "d.objsubid = 0 AND "
    6335             :                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
    6336             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
    6337             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
    6338             :                           "ORDER BY c.oid",
    6339             :                           username_subquery,
    6340             :                           RELKIND_SEQUENCE,
    6341             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6342             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
    6343             :     }
    6344           0 :     else if (fout->remoteVersion >= 80400)
    6345             :     {
    6346             :         /*
    6347             :          * Left join to pick up dependency info linking sequences to their
    6348             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6349             :          */
    6350           0 :         appendPQExpBuffer(query,
    6351             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6352             :                           "c.relacl, NULL as rrelacl, "
    6353             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6354             :                           "c.relkind, "
    6355             :                           "c.relnamespace, "
    6356             :                           "(%s c.relowner) AS rolname, "
    6357             :                           "c.relchecks, c.relhastriggers, "
    6358             :                           "c.relhasindex, c.relhasrules, c.relhasoids, "
    6359             :                           "'f'::bool AS relrowsecurity, "
    6360             :                           "'f'::bool AS relforcerowsecurity, "
    6361             :                           "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
    6362             :                           "tc.relfrozenxid AS tfrozenxid, "
    6363             :                           "0 AS tminmxid, "
    6364             :                           "'p' AS relpersistence, 't' as relispopulated, "
    6365             :                           "'d' AS relreplident, c.relpages, "
    6366             :                           "NULL AS amname, "
    6367             :                           "NULL AS reloftype, "
    6368             :                           "d.refobjid AS owning_tab, "
    6369             :                           "d.refobjsubid AS owning_col, "
    6370             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6371             :                           "c.reloptions AS reloptions, "
    6372             :                           "tc.reloptions AS toast_reloptions, "
    6373             :                           "NULL AS changed_acl, "
    6374             :                           "NULL AS partkeydef, "
    6375             :                           "false AS ispartition, "
    6376             :                           "NULL AS partbound "
    6377             :                           "FROM pg_class c "
    6378             :                           "LEFT JOIN pg_depend d ON "
    6379             :                           "(c.relkind = '%c' AND "
    6380             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6381             :                           "d.objsubid = 0 AND "
    6382             :                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
    6383             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
    6384             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
    6385             :                           "ORDER BY c.oid",
    6386             :                           username_subquery,
    6387             :                           RELKIND_SEQUENCE,
    6388             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6389             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
    6390             :     }
    6391           0 :     else if (fout->remoteVersion >= 80200)
    6392             :     {
    6393             :         /*
    6394             :          * Left join to pick up dependency info linking sequences to their
    6395             :          * owning column, if any (note this dependency is AUTO as of 8.2)
    6396             :          */
    6397           0 :         appendPQExpBuffer(query,
    6398             :                           "SELECT c.tableoid, c.oid, c.relname, "
    6399             :                           "c.relacl, NULL as rrelacl, "
    6400             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6401             :                           "c.relkind, "
    6402             :                           "c.relnamespace, "
    6403             :                           "(%s c.relowner) AS rolname, "
    6404             :                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
    6405             :                           "c.relhasindex, c.relhasrules, c.relhasoids, "
    6406             :                           "'f'::bool AS relrowsecurity, "
    6407             :                           "'f'::bool AS relforcerowsecurity, "
    6408             :                           "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
    6409             :                           "tc.relfrozenxid AS tfrozenxid, "
    6410             :                           "0 AS tminmxid, "
    6411             :                           "'p' AS relpersistence, 't' as relispopulated, "
    6412             :                           "'d' AS relreplident, c.relpages, "
    6413             :                           "NULL AS amname, "
    6414             :                           "NULL AS reloftype, "
    6415             :                           "d.refobjid AS owning_tab, "
    6416             :                           "d.refobjsubid AS owning_col, "
    6417             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6418             :                           "c.reloptions AS reloptions, "
    6419             :                           "NULL AS toast_reloptions, "
    6420             :                           "NULL AS changed_acl, "
    6421             :                           "NULL AS partkeydef, "
    6422             :                           "false AS ispartition, "
    6423             :                           "NULL AS partbound "
    6424             :                           "FROM pg_class c "
    6425             :                           "LEFT JOIN pg_depend d ON "
    6426             :                           "(c.relkind = '%c' AND "
    6427             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6428             :                           "d.objsubid = 0 AND "
    6429             :                           "d.refclassid = c.tableoid AND d.deptype = 'a') "
    6430             :                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
    6431             :                           "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
    6432             :                           "ORDER BY c.oid",
    6433             :                           username_subquery,
    6434             :                           RELKIND_SEQUENCE,
    6435             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6436             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
    6437             :     }
    6438             :     else
    6439             :     {
    6440             :         /*
    6441             :          * Left join to pick up dependency info linking sequences to their
    6442             :          * owning column, if any
    6443             :          */
    6444           0 :         appendPQExpBuffer(query,
    6445             :                           "SELECT c.tableoid, c.oid, relname, "
    6446             :                           "relacl, NULL as rrelacl, "
    6447             :                           "NULL AS initrelacl, NULL AS initrrelacl, "
    6448             :                           "relkind, relnamespace, "
    6449             :                           "(%s relowner) AS rolname, "
    6450             :                           "relchecks, (reltriggers <> 0) AS relhastriggers, "
    6451             :                           "relhasindex, relhasrules, relhasoids, "
    6452             :                           "'f'::bool AS relrowsecurity, "
    6453             :                           "'f'::bool AS relforcerowsecurity, "
    6454             :                           "0 AS relfrozenxid, 0 AS relminmxid,"
    6455             :                           "0 AS toid, "
    6456             :                           "0 AS tfrozenxid, 0 AS tminmxid,"
    6457             :                           "'p' AS relpersistence, 't' as relispopulated, "
    6458             :                           "'d' AS relreplident, relpages, "
    6459             :                           "NULL AS amname, "
    6460             :                           "NULL AS reloftype, "
    6461             :                           "d.refobjid AS owning_tab, "
    6462             :                           "d.refobjsubid AS owning_col, "
    6463             :                           "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
    6464             :                           "NULL AS reloptions, "
    6465             :                           "NULL AS toast_reloptions, "
    6466             :                           "NULL AS changed_acl, "
    6467             :                           "NULL AS partkeydef, "
    6468             :                           "false AS ispartition, "
    6469             :                           "NULL AS partbound "
    6470             :                           "FROM pg_class c "
    6471             :                           "LEFT JOIN pg_depend d ON "
    6472             :                           "(c.relkind = '%c' AND "
    6473             :                           "d.classid = c.tableoid AND d.objid = c.oid AND "
    6474             :                           "d.objsubid = 0 AND "
    6475             :                           "d.refclassid = c.tableoid AND d.deptype = 'i') "
    6476             :                           "WHERE relkind in ('%c', '%c', '%c', '%c') "
    6477             :                           "ORDER BY c.oid",
    6478             :                           username_subquery,
    6479             :                           RELKIND_SEQUENCE,
    6480             :                           RELKIND_RELATION, RELKIND_SEQUENCE,
    6481             :                           RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
    6482             :     }
    6483             : 
    6484         158 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6485             : 
    6486         158 :     ntups = PQntuples(res);
    6487             : 
    6488         158 :     *numTables = ntups;
    6489             : 
    6490             :     /*
    6491             :      * Extract data from result and lock dumpable tables.  We do the locking
    6492             :      * before anything else, to minimize the window wherein a table could
    6493             :      * disappear under us.
    6494             :      *
    6495             :      * Note that we have to save info about all tables here, even when dumping
    6496             :      * only one, because we don't yet know which tables might be inheritance
    6497             :      * ancestors of the target table.
    6498             :      */
    6499         158 :     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    6500             : 
    6501         158 :     i_reltableoid = PQfnumber(res, "tableoid");
    6502         158 :     i_reloid = PQfnumber(res, "oid");
    6503         158 :     i_relname = PQfnumber(res, "relname");
    6504         158 :     i_relnamespace = PQfnumber(res, "relnamespace");
    6505         158 :     i_relacl = PQfnumber(res, "relacl");
    6506         158 :     i_rrelacl = PQfnumber(res, "rrelacl");
    6507         158 :     i_initrelacl = PQfnumber(res, "initrelacl");
    6508         158 :     i_initrrelacl = PQfnumber(res, "initrrelacl");
    6509         158 :     i_relkind = PQfnumber(res, "relkind");
    6510         158 :     i_rolname = PQfnumber(res, "rolname");
    6511         158 :     i_relchecks = PQfnumber(res, "relchecks");
    6512         158 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    6513         158 :     i_relhasindex = PQfnumber(res, "relhasindex");
    6514         158 :     i_relhasrules = PQfnumber(res, "relhasrules");
    6515         158 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    6516         158 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    6517         158 :     i_relhasoids = PQfnumber(res, "relhasoids");
    6518         158 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    6519         158 :     i_relminmxid = PQfnumber(res, "relminmxid");
    6520         158 :     i_toastoid = PQfnumber(res, "toid");
    6521         158 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    6522         158 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    6523         158 :     i_relpersistence = PQfnumber(res, "relpersistence");
    6524         158 :     i_relispopulated = PQfnumber(res, "relispopulated");
    6525         158 :     i_relreplident = PQfnumber(res, "relreplident");
    6526         158 :     i_relpages = PQfnumber(res, "relpages");
    6527         158 :     i_owning_tab = PQfnumber(res, "owning_tab");
    6528         158 :     i_owning_col = PQfnumber(res, "owning_col");
    6529         158 :     i_reltablespace = PQfnumber(res, "reltablespace");
    6530         158 :     i_reloptions = PQfnumber(res, "reloptions");
    6531         158 :     i_checkoption = PQfnumber(res, "checkoption");
    6532         158 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    6533         158 :     i_reloftype = PQfnumber(res, "reloftype");
    6534         158 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    6535         158 :     i_changed_acl = PQfnumber(res, "changed_acl");
    6536         158 :     i_partkeydef = PQfnumber(res, "partkeydef");
    6537         158 :     i_ispartition = PQfnumber(res, "ispartition");
    6538         158 :     i_partbound = PQfnumber(res, "partbound");
    6539         158 :     i_amname = PQfnumber(res, "amname");
    6540             : 
    6541         158 :     if (dopt->lockWaitTimeout)
    6542             :     {
    6543             :         /*
    6544             :          * Arrange to fail instead of waiting forever for a table lock.
    6545             :          *
    6546             :          * NB: this coding assumes that the only queries issued within the
    6547             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    6548             :          * applied to other things too.
    6549             :          */
    6550           2 :         resetPQExpBuffer(query);
    6551           2 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    6552           2 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    6553           2 :         ExecuteSqlStatement(fout, query->data);
    6554             :     }
    6555             : 
    6556       36122 :     for (i = 0; i < ntups; i++)
    6557             :     {
    6558       35966 :         tblinfo[i].dobj.objType = DO_TABLE;
    6559       35966 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    6560       35966 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    6561       35966 :         AssignDumpId(&tblinfo[i].dobj);
    6562       35966 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    6563       71932 :         tblinfo[i].dobj.namespace =
    6564       35966 :             findNamespace(fout,
    6565       35966 :                           atooid(PQgetvalue(res, i, i_relnamespace)));
    6566       35966 :         tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    6567       35966 :         tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
    6568       35966 :         tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
    6569       35966 :         tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
    6570       35966 :         tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
    6571       35966 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    6572       35966 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    6573       35966 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    6574       35966 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    6575       35966 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    6576       35966 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    6577       35966 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    6578       35966 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    6579       35966 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    6580       35966 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    6581       35966 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    6582       35966 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    6583       35966 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    6584       35966 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    6585       35966 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    6586       35966 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    6587       35966 :         if (PQgetisnull(res, i, i_reloftype))
    6588       35924 :             tblinfo[i].reloftype = NULL;
    6589             :         else
    6590          42 :             tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
    6591       35966 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    6592       35966 :         if (PQgetisnull(res, i, i_owning_tab))
    6593             :         {
    6594       35632 :             tblinfo[i].owning_tab = InvalidOid;
    6595       35632 :             tblinfo[i].owning_col = 0;
    6596             :         }
    6597             :         else
    6598             :         {
    6599         334 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    6600         334 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    6601             :         }
    6602       35966 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    6603       35966 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    6604       35966 :         if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
    6605       35908 :             tblinfo[i].checkoption = NULL;
    6606             :         else
    6607          58 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    6608       35966 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    6609       35966 :         if (PQgetisnull(res, i, i_amname))
    6610       21172 :             tblinfo[i].amname = NULL;
    6611             :         else
    6612       14794 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    6613             : 
    6614             :         /* other fields were zeroed above */
    6615             : 
    6616             :         /*
    6617             :          * Decide whether we want to dump this table.
    6618             :          */
    6619       35966 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    6620         186 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    6621             :         else
    6622       35780 :             selectDumpableTable(&tblinfo[i], fout);
    6623             : 
    6624             :         /*
    6625             :          * If the table-level and all column-level ACLs for this table are
    6626             :          * unchanged, then we don't need to worry about including the ACLs for
    6627             :          * this table.  If any column-level ACLs have been changed, the
    6628             :          * 'changed_acl' column from the query will indicate that.
    6629             :          *
    6630             :          * This can result in a significant performance improvement in cases
    6631             :          * where we are only looking to dump out the ACL (eg: pg_catalog).
    6632             :          */
    6633       62434 :         if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
    6634       52928 :             PQgetisnull(res, i, i_initrelacl) &&
    6635       52920 :             PQgetisnull(res, i, i_initrrelacl) &&
    6636       26460 :             strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
    6637       26360 :             tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    6638             : 
    6639       35966 :         tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
    6640       35966 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    6641       35966 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    6642             : 
    6643       71932 :         tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
    6644       35966 :                                            strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    6645             : 
    6646             :         /* Partition key string or NULL */
    6647       35966 :         tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
    6648       35966 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    6649       35966 :         tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
    6650             : 
    6651             :         /*
    6652             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    6653             :          * in schema before we get around to dumping them.
    6654             :          *
    6655             :          * Note that we don't explicitly lock parents of the target tables; we
    6656             :          * assume our lock on the child is enough to prevent schema
    6657             :          * alterations to parent tables.
    6658             :          *
    6659             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    6660             :          * plain or partitioned tables, but the backend doesn't presently
    6661             :          * allow that.
    6662             :          *
    6663             :          * We only need to lock the table for certain components; see
    6664             :          * pg_dump.h
    6665             :          */
    6666       41344 :         if (tblinfo[i].dobj.dump &&
    6667        7080 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    6668        5378 :              tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
    6669        3676 :             (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
    6670             :         {
    6671        3616 :             resetPQExpBuffer(query);
    6672        3616 :             appendPQExpBuffer(query,
    6673             :                               "LOCK TABLE %s IN ACCESS SHARE MODE",
    6674        3616 :                               fmtQualifiedDumpable(&tblinfo[i]));
    6675        3616 :             ExecuteSqlStatement(fout, query->data);
    6676             :         }
    6677             : 
    6678             :         /* Emit notice if join for owner failed */
    6679       35964 :         if (strlen(tblinfo[i].rolname) == 0)
    6680           0 :             pg_log_warning("owner of table \"%s\" appears to be invalid",
    6681             :                            tblinfo[i].dobj.name);
    6682             :     }
    6683             : 
    6684         156 :     if (dopt->lockWaitTimeout)
    6685             :     {
    6686           2 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    6687             :     }
    6688             : 
    6689         156 :     PQclear(res);
    6690             : 
    6691         156 :     destroyPQExpBuffer(query);
    6692             : 
    6693         156 :     return tblinfo;
    6694             : }
    6695             : 
    6696             : /*
    6697             :  * getOwnedSeqs
    6698             :  *    identify owned sequences and mark them as dumpable if owning table is
    6699             :  *
    6700             :  * We used to do this in getTables(), but it's better to do it after the
    6701             :  * index used by findTableByOid() has been set up.
    6702             :  */
    6703             : void
    6704         156 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    6705             : {
    6706             :     int         i;
    6707             : 
    6708             :     /*
    6709             :      * Force sequences that are "owned" by table columns to be dumped whenever
    6710             :      * their owning table is being dumped.
    6711             :      */
    6712       35736 :     for (i = 0; i < numTables; i++)
    6713             :     {
    6714       35580 :         TableInfo  *seqinfo = &tblinfo[i];
    6715             :         TableInfo  *owning_tab;
    6716             : 
    6717       35580 :         if (!OidIsValid(seqinfo->owning_tab))
    6718       35248 :             continue;           /* not an owned sequence */
    6719             : 
    6720         332 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    6721         332 :         if (owning_tab == NULL)
    6722           0 :             fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    6723             :                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    6724             : 
    6725             :         /*
    6726             :          * Only dump identity sequences if we're going to dump the table that
    6727             :          * it belongs to.
    6728             :          */
    6729         360 :         if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
    6730          28 :             seqinfo->is_identity_sequence)
    6731             :         {
    6732          10 :             seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6733          10 :             continue;
    6734             :         }
    6735             : 
    6736             :         /*
    6737             :          * Otherwise we need to dump the components that are being dumped for
    6738             :          * the table and any components which the sequence is explicitly
    6739             :          * marked with.
    6740             :          *
    6741             :          * We can't simply use the set of components which are being dumped
    6742             :          * for the table as the table might be in an extension (and only the
    6743             :          * non-extension components, eg: ACLs if changed, security labels, and
    6744             :          * policies, are being dumped) while the sequence is not (and
    6745             :          * therefore the definition and other components should also be
    6746             :          * dumped).
    6747             :          *
    6748             :          * If the sequence is part of the extension then it should be properly
    6749             :          * marked by checkExtensionMembership() and this will be a no-op as
    6750             :          * the table will be equivalently marked.
    6751             :          */
    6752         322 :         seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
    6753             : 
    6754         322 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    6755         306 :             seqinfo->interesting = true;
    6756             :     }
    6757         156 : }
    6758             : 
    6759             : /*
    6760             :  * getInherits
    6761             :  *    read all the inheritance information
    6762             :  * from the system catalogs return them in the InhInfo* structure
    6763             :  *
    6764             :  * numInherits is set to the number of pairs read in
    6765             :  */
    6766             : InhInfo *
    6767         156 : getInherits(Archive *fout, int *numInherits)
    6768             : {
    6769             :     PGresult   *res;
    6770             :     int         ntups;
    6771             :     int         i;
    6772         156 :     PQExpBuffer query = createPQExpBuffer();
    6773             :     InhInfo    *inhinfo;
    6774             : 
    6775             :     int         i_inhrelid;
    6776             :     int         i_inhparent;
    6777             : 
    6778             :     /*
    6779             :      * Find all the inheritance information, excluding implicit inheritance
    6780             :      * via partitioning.
    6781             :      */
    6782         156 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    6783             : 
    6784         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6785             : 
    6786         156 :     ntups = PQntuples(res);
    6787             : 
    6788         156 :     *numInherits = ntups;
    6789             : 
    6790         156 :     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    6791             : 
    6792         156 :     i_inhrelid = PQfnumber(res, "inhrelid");
    6793         156 :     i_inhparent = PQfnumber(res, "inhparent");
    6794             : 
    6795        1856 :     for (i = 0; i < ntups; i++)
    6796             :     {
    6797        1700 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    6798        1700 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    6799             :     }
    6800             : 
    6801         156 :     PQclear(res);
    6802             : 
    6803         156 :     destroyPQExpBuffer(query);
    6804             : 
    6805         156 :     return inhinfo;
    6806             : }
    6807             : 
    6808             : /*
    6809             :  * getIndexes
    6810             :  *    get information about every index on a dumpable table
    6811             :  *
    6812             :  * Note: index data is not returned directly to the caller, but it
    6813             :  * does get entered into the DumpableObject tables.
    6814             :  */
    6815             : void
    6816         156 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    6817             : {
    6818             :     int         i,
    6819             :                 j;
    6820         156 :     PQExpBuffer query = createPQExpBuffer();
    6821             :     PGresult   *res;
    6822             :     IndxInfo   *indxinfo;
    6823             :     ConstraintInfo *constrinfo;
    6824             :     int         i_tableoid,
    6825             :                 i_oid,
    6826             :                 i_indexname,
    6827             :                 i_parentidx,
    6828             :                 i_indexdef,
    6829             :                 i_indnkeyatts,
    6830             :                 i_indnatts,
    6831             :                 i_indkey,
    6832             :                 i_indisclustered,
    6833             :                 i_indisreplident,
    6834             :                 i_contype,
    6835             :                 i_conname,
    6836             :                 i_condeferrable,
    6837             :                 i_condeferred,
    6838             :                 i_contableoid,
    6839             :                 i_conoid,
    6840             :                 i_condef,
    6841             :                 i_tablespace,
    6842             :                 i_indreloptions,
    6843             :                 i_indstatcols,
    6844             :                 i_indstatvals;
    6845             :     int         ntups;
    6846             : 
    6847       35736 :     for (i = 0; i < numTables; i++)
    6848             :     {
    6849       35580 :         TableInfo  *tbinfo = &tblinfo[i];
    6850             : 
    6851       35580 :         if (!tbinfo->hasindex)
    6852       24340 :             continue;
    6853             : 
    6854             :         /*
    6855             :          * Ignore indexes of tables whose definitions are not to be dumped.
    6856             :          *
    6857             :          * We also need indexes on partitioned tables which have partitions to
    6858             :          * be dumped, in order to dump the indexes on the partitions.
    6859             :          */
    6860       21134 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6861        9894 :             !tbinfo->interesting)
    6862        9830 :             continue;
    6863             : 
    6864        1410 :         pg_log_info("reading indexes for table \"%s.%s\"",
    6865             :                     tbinfo->dobj.namespace->dobj.name,
    6866             :                     tbinfo->dobj.name);
    6867             : 
    6868             :         /*
    6869             :          * The point of the messy-looking outer join is to find a constraint
    6870             :          * that is related by an internal dependency link to the index. If we
    6871             :          * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
    6872             :          * assume an index won't have more than one internal dependency.
    6873             :          *
    6874             :          * As of 9.0 we don't need to look at pg_depend but can check for a
    6875             :          * match to pg_constraint.conindid.  The check on conrelid is
    6876             :          * redundant but useful because that column is indexed while conindid
    6877             :          * is not.
    6878             :          */
    6879        1410 :         resetPQExpBuffer(query);
    6880        1410 :         if (fout->remoteVersion >= 110000)
    6881             :         {
    6882        1410 :             appendPQExpBuffer(query,
    6883             :                               "SELECT t.tableoid, t.oid, "
    6884             :                               "t.relname AS indexname, "
    6885             :                               "inh.inhparent AS parentidx, "
    6886             :                               "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    6887             :                               "i.indnkeyatts AS indnkeyatts, "
    6888             :                               "i.indnatts AS indnatts, "
    6889             :                               "i.indkey, i.indisclustered, "
    6890             :                               "i.indisreplident, "
    6891             :                               "c.contype, c.conname, "
    6892             :                               "c.condeferrable, c.condeferred, "
    6893             :                               "c.tableoid AS contableoid, "
    6894             :                               "c.oid AS conoid, "
    6895             :                               "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    6896             :                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    6897             :                               "t.reloptions AS indreloptions, "
    6898             :                               "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    6899             :                               "  FROM pg_catalog.pg_attribute "
    6900             :                               "  WHERE attrelid = i.indexrelid AND "
    6901             :                               "    attstattarget >= 0) AS indstatcols,"
    6902             :                               "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    6903             :                               "  FROM pg_catalog.pg_attribute "
    6904             :                               "  WHERE attrelid = i.indexrelid AND "
    6905             :                               "    attstattarget >= 0) AS indstatvals "
    6906             :                               "FROM pg_catalog.pg_index i "
    6907             :                               "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    6908             :                               "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    6909             :                               "LEFT JOIN pg_catalog.pg_constraint c "
    6910             :                               "ON (i.indrelid = c.conrelid AND "
    6911             :                               "i.indexrelid = c.conindid AND "
    6912             :                               "c.contype IN ('p','u','x')) "
    6913             :                               "LEFT JOIN pg_catalog.pg_inherits inh "
    6914             :                               "ON (inh.inhrelid = indexrelid) "
    6915             :                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
    6916             :                               "AND (i.indisvalid OR t2.relkind = 'p') "
    6917             :                               "AND i.indisready "
    6918             :                               "ORDER BY indexname",
    6919             :                               tbinfo->dobj.catId.oid);
    6920             :         }
    6921           0 :         else if (fout->remoteVersion >= 90400)
    6922             :         {
    6923             :             /*
    6924             :              * the test on indisready is necessary in 9.2, and harmless in
    6925             :              * earlier/later versions
    6926             :              */
    6927           0 :             appendPQExpBuffer(query,
    6928             :                               "SELECT t.tableoid, t.oid, "
    6929             :                               "t.relname AS indexname, "
    6930             :                               "0 AS parentidx, "
    6931             :                               "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    6932             :                               "i.indnatts AS indnkeyatts, "
    6933             :                               "i.indnatts AS indnatts, "
    6934             :                               "i.indkey, i.indisclustered, "
    6935             :                               "i.indisreplident, "
    6936             :                               "c.contype, c.conname, "
    6937             :                               "c.condeferrable, c.condeferred, "
    6938             :                               "c.tableoid AS contableoid, "
    6939             :                               "c.oid AS conoid, "
    6940             :                               "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    6941             :                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    6942             :                               "t.reloptions AS indreloptions, "
    6943             :                               "'' AS indstatcols, "
    6944             :                               "'' AS indstatvals "
    6945             :                               "FROM pg_catalog.pg_index i "
    6946             :                               "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    6947             :                               "LEFT JOIN pg_catalog.pg_constraint c "
    6948             :                               "ON (i.indrelid = c.conrelid AND "
    6949             :                               "i.indexrelid = c.conindid AND "
    6950             :                               "c.contype IN ('p','u','x')) "
    6951             :                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
    6952             :                               "AND i.indisvalid AND i.indisready "
    6953             :                               "ORDER BY indexname",
    6954             :                               tbinfo->dobj.catId.oid);
    6955             :         }
    6956           0 :         else if (fout->remoteVersion >= 90000)
    6957             :         {
    6958             :             /*
    6959             :              * the test on indisready is necessary in 9.2, and harmless in
    6960             :              * earlier/later versions
    6961             :              */
    6962           0 :             appendPQExpBuffer(query,
    6963             :                               "SELECT t.tableoid, t.oid, "
    6964             :                               "t.relname AS indexname, "
    6965             :                               "0 AS parentidx, "
    6966             :                               "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    6967             :                               "i.indnatts AS indnkeyatts, "
    6968             :                               "i.indnatts AS indnatts, "
    6969             :                               "i.indkey, i.indisclustered, "
    6970             :                               "false AS indisreplident, "
    6971             :                               "c.contype, c.conname, "
    6972             :                               "c.condeferrable, c.condeferred, "
    6973             :                               "c.tableoid AS contableoid, "
    6974             :                               "c.oid AS conoid, "
    6975             :                               "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    6976             :                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    6977             :                               "t.reloptions AS indreloptions, "
    6978             :                               "'' AS indstatcols, "
    6979             :                               "'' AS indstatvals "
    6980             :                               "FROM pg_catalog.pg_index i "
    6981             :                               "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    6982             :                               "LEFT JOIN pg_catalog.pg_constraint c "
    6983             :                               "ON (i.indrelid = c.conrelid AND "
    6984             :                               "i.indexrelid = c.conindid AND "
    6985             :                               "c.contype IN ('p','u','x')) "
    6986             :                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
    6987             :                               "AND i.indisvalid AND i.indisready "
    6988             :                               "ORDER BY indexname",
    6989             :                               tbinfo->dobj.catId.oid);
    6990             :         }
    6991           0 :         else if (fout->remoteVersion >= 80200)
    6992             :         {
    6993           0 :             appendPQExpBuffer(query,
    6994             :                               "SELECT t.tableoid, t.oid, "
    6995             :                               "t.relname AS indexname, "
    6996             :                               "0 AS parentidx, "
    6997             :                               "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    6998             :                               "i.indnatts AS indnkeyatts, "
    6999             :                               "i.indnatts AS indnatts, "
    7000             :                               "i.indkey, i.indisclustered, "
    7001             :                               "false AS indisreplident, "
    7002             :                               "c.contype, c.conname, "
    7003             :                               "c.condeferrable, c.condeferred, "
    7004             :                               "c.tableoid AS contableoid, "
    7005             :                               "c.oid AS conoid, "
    7006             :                               "null AS condef, "
    7007             :                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7008             :                               "t.reloptions AS indreloptions, "
    7009             :                               "'' AS indstatcols, "
    7010             :                               "'' AS indstatvals "
    7011             :                               "FROM pg_catalog.pg_index i "
    7012             :                               "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7013             :                               "LEFT JOIN pg_catalog.pg_depend d "
    7014             :                               "ON (d.classid = t.tableoid "
    7015             :                               "AND d.objid = t.oid "
    7016             :                               "AND d.deptype = 'i') "
    7017             :                               "LEFT JOIN pg_catalog.pg_constraint c "
    7018             :                               "ON (d.refclassid = c.tableoid "
    7019             :                               "AND d.refobjid = c.oid) "
    7020             :                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
    7021             :                               "AND i.indisvalid "
    7022             :                               "ORDER BY indexname",
    7023             :                               tbinfo->dobj.catId.oid);
    7024             :         }
    7025             :         else
    7026             :         {
    7027           0 :             appendPQExpBuffer(query,
    7028             :                               "SELECT t.tableoid, t.oid, "
    7029             :                               "t.relname AS indexname, "
    7030             :                               "0 AS parentidx, "
    7031             :                               "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7032             :                               "t.relnatts AS indnkeyatts, "
    7033             :                               "t.relnatts AS indnatts, "
    7034             :                               "i.indkey, i.indisclustered, "
    7035             :                               "false AS indisreplident, "
    7036             :                               "c.contype, c.conname, "
    7037             :                               "c.condeferrable, c.condeferred, "
    7038             :                               "c.tableoid AS contableoid, "
    7039             :                               "c.oid AS conoid, "
    7040             :                               "null AS condef, "
    7041             :                               "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7042             :                               "null AS indreloptions, "
    7043             :                               "'' AS indstatcols, "
    7044             :                               "'' AS indstatvals "
    7045             :                               "FROM pg_catalog.pg_index i "
    7046             :                               "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7047             :                               "LEFT JOIN pg_catalog.pg_depend d "
    7048             :                               "ON (d.classid = t.tableoid "
    7049             :                               "AND d.objid = t.oid "
    7050             :                               "AND d.deptype = 'i') "
    7051             :                               "LEFT JOIN pg_catalog.pg_constraint c "
    7052             :                               "ON (d.refclassid = c.tableoid "
    7053             :                               "AND d.refobjid = c.oid) "
    7054             :                               "WHERE i.indrelid = '%u'::pg_catalog.oid "
    7055             :                               "ORDER BY indexname",
    7056             :                               tbinfo->dobj.catId.oid);
    7057             :         }
    7058             : 
    7059        1410 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7060             : 
    7061        1410 :         ntups = PQntuples(res);
    7062             : 
    7063        1410 :         i_tableoid = PQfnumber(res, "tableoid");
    7064        1410 :         i_oid = PQfnumber(res, "oid");
    7065        1410 :         i_indexname = PQfnumber(res, "indexname");
    7066        1410 :         i_parentidx = PQfnumber(res, "parentidx");
    7067        1410 :         i_indexdef = PQfnumber(res, "indexdef");
    7068        1410 :         i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    7069        1410 :         i_indnatts = PQfnumber(res, "indnatts");
    7070        1410 :         i_indkey = PQfnumber(res, "indkey");
    7071        1410 :         i_indisclustered = PQfnumber(res, "indisclustered");
    7072        1410 :         i_indisreplident = PQfnumber(res, "indisreplident");
    7073        1410 :         i_contype = PQfnumber(res, "contype");
    7074        1410 :         i_conname = PQfnumber(res, "conname");
    7075        1410 :         i_condeferrable = PQfnumber(res, "condeferrable");
    7076        1410 :         i_condeferred = PQfnumber(res, "condeferred");
    7077        1410 :         i_contableoid = PQfnumber(res, "contableoid");
    7078        1410 :         i_conoid = PQfnumber(res, "conoid");
    7079        1410 :         i_condef = PQfnumber(res, "condef");
    7080        1410 :         i_tablespace = PQfnumber(res, "tablespace");
    7081        1410 :         i_indreloptions = PQfnumber(res, "indreloptions");
    7082        1410 :         i_indstatcols = PQfnumber(res, "indstatcols");
    7083        1410 :         i_indstatvals = PQfnumber(res, "indstatvals");
    7084             : 
    7085        1410 :         tbinfo->indexes = indxinfo =
    7086        1410 :             (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    7087        1410 :         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    7088        1410 :         tbinfo->numIndexes = ntups;
    7089             : 
    7090        3200 :         for (j = 0; j < ntups; j++)
    7091             :         {
    7092             :             char        contype;
    7093             : 
    7094        1790 :             indxinfo[j].dobj.objType = DO_INDEX;
    7095        1790 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    7096        1790 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    7097        1790 :             AssignDumpId(&indxinfo[j].dobj);
    7098        1790 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    7099        1790 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    7100        1790 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7101        1790 :             indxinfo[j].indextable = tbinfo;
    7102        1790 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    7103        1790 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    7104        1790 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    7105        1790 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    7106        1790 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    7107        1790 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    7108        1790 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    7109        1790 :             indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    7110        3580 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    7111        3580 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    7112        1790 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    7113        1790 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    7114        1790 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    7115        1790 :             indxinfo[j].partattaches = (SimplePtrList) { NULL, NULL };
    7116        1790 :             contype = *(PQgetvalue(res, j, i_contype));
    7117             : 
    7118        1790 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    7119             :             {
    7120             :                 /*
    7121             :                  * If we found a constraint matching the index, create an
    7122             :                  * entry for it.
    7123             :                  */
    7124         796 :                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
    7125         796 :                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7126         796 :                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7127         796 :                 AssignDumpId(&constrinfo[j].dobj);
    7128         796 :                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
    7129         796 :                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7130         796 :                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7131         796 :                 constrinfo[j].contable = tbinfo;
    7132         796 :                 constrinfo[j].condomain = NULL;
    7133         796 :                 constrinfo[j].contype = contype;
    7134         796 :                 if (contype == 'x')
    7135          12 :                     constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7136             :                 else
    7137         784 :                     constrinfo[j].condef = NULL;
    7138         796 :                 constrinfo[j].confrelid = InvalidOid;
    7139         796 :                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
    7140         796 :                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    7141         796 :                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    7142         796 :                 constrinfo[j].conislocal = true;
    7143         796 :                 constrinfo[j].separate = true;
    7144             : 
    7145         796 :                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
    7146             :             }
    7147             :             else
    7148             :             {
    7149             :                 /* Plain secondary index */
    7150         994 :                 indxinfo[j].indexconstraint = 0;
    7151             :             }
    7152             :         }
    7153             : 
    7154        1410 :         PQclear(res);
    7155             :     }
    7156             : 
    7157         156 :     destroyPQExpBuffer(query);
    7158         156 : }
    7159             : 
    7160             : /*
    7161             :  * getExtendedStatistics
    7162             :  *    get information about extended-statistics objects.
    7163             :  *
    7164             :  * Note: extended statistics data is not returned directly to the caller, but
    7165             :  * it does get entered into the DumpableObject tables.
    7166             :  */
    7167             : void
    7168         156 : getExtendedStatistics(Archive *fout)
    7169             : {
    7170             :     PQExpBuffer query;
    7171             :     PGresult   *res;
    7172             :     StatsExtInfo *statsextinfo;
    7173             :     int         ntups;
    7174             :     int         i_tableoid;
    7175             :     int         i_oid;
    7176             :     int         i_stxname;
    7177             :     int         i_stxnamespace;
    7178             :     int         i_rolname;
    7179             :     int         i_stattarget;
    7180             :     int         i;
    7181             : 
    7182             :     /* Extended statistics were new in v10 */
    7183         156 :     if (fout->remoteVersion < 100000)
    7184           0 :         return;
    7185             : 
    7186         156 :     query = createPQExpBuffer();
    7187             : 
    7188         156 :     if (fout->remoteVersion < 130000)
    7189           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
    7190             :                           "stxnamespace, (%s stxowner) AS rolname, (-1) AS stxstattarget "
    7191             :                           "FROM pg_catalog.pg_statistic_ext",
    7192             :                           username_subquery);
    7193             :     else
    7194         156 :         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
    7195             :                           "stxnamespace, (%s stxowner) AS rolname, stxstattarget "
    7196             :                           "FROM pg_catalog.pg_statistic_ext",
    7197             :                           username_subquery);
    7198             : 
    7199         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7200             : 
    7201         156 :     ntups = PQntuples(res);
    7202             : 
    7203         156 :     i_tableoid = PQfnumber(res, "tableoid");
    7204         156 :     i_oid = PQfnumber(res, "oid");
    7205         156 :     i_stxname = PQfnumber(res, "stxname");
    7206         156 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    7207         156 :     i_rolname = PQfnumber(res, "rolname");
    7208         156 :     i_stattarget = PQfnumber(res, "stxstattarget");
    7209             : 
    7210         156 :     statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    7211             : 
    7212         296 :     for (i = 0; i < ntups; i++)
    7213             :     {
    7214         140 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    7215         140 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7216         140 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7217         140 :         AssignDumpId(&statsextinfo[i].dobj);
    7218         140 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    7219         280 :         statsextinfo[i].dobj.namespace =
    7220         140 :             findNamespace(fout,
    7221         140 :                           atooid(PQgetvalue(res, i, i_stxnamespace)));
    7222         140 :         statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    7223         140 :         statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    7224             : 
    7225             :         /* Decide whether we want to dump it */
    7226         140 :         selectDumpableObject(&(statsextinfo[i].dobj), fout);
    7227             : 
    7228             :         /* Stats objects do not currently have ACLs. */
    7229         140 :         statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    7230             :     }
    7231             : 
    7232         156 :     PQclear(res);
    7233         156 :     destroyPQExpBuffer(query);
    7234             : }
    7235             : 
    7236             : /*
    7237             :  * getConstraints
    7238             :  *
    7239             :  * Get info about constraints on dumpable tables.
    7240             :  *
    7241             :  * Currently handles foreign keys only.
    7242             :  * Unique and primary key constraints are handled with indexes,
    7243             :  * while check constraints are processed in getTableAttrs().
    7244             :  */
    7245             : void
    7246         156 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    7247             : {
    7248             :     int         i,
    7249             :                 j;
    7250             :     ConstraintInfo *constrinfo;
    7251             :     PQExpBuffer query;
    7252             :     PGresult   *res;
    7253             :     int         i_contableoid,
    7254             :                 i_conoid,
    7255             :                 i_conname,
    7256             :                 i_confrelid,
    7257             :                 i_conindid,
    7258             :                 i_condef;
    7259             :     int         ntups;
    7260             : 
    7261         156 :     query = createPQExpBuffer();
    7262             : 
    7263       35736 :     for (i = 0; i < numTables; i++)
    7264             :     {
    7265       35580 :         TableInfo  *tbinfo = &tblinfo[i];
    7266             : 
    7267             :         /*
    7268             :          * For partitioned tables, foreign keys have no triggers so they must
    7269             :          * be included anyway in case some foreign keys are defined.
    7270             :          */
    7271       70632 :         if ((!tbinfo->hastriggers &&
    7272       36068 :              tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
    7273        1016 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    7274       34612 :             continue;
    7275             : 
    7276         968 :         pg_log_info("reading foreign key constraints for table \"%s.%s\"",
    7277             :                     tbinfo->dobj.namespace->dobj.name,
    7278             :                     tbinfo->dobj.name);
    7279             : 
    7280         968 :         resetPQExpBuffer(query);
    7281         968 :         if (fout->remoteVersion >= 110000)
    7282         968 :             appendPQExpBuffer(query,
    7283             :                               "SELECT tableoid, oid, conname, confrelid, conindid, "
    7284             :                               "pg_catalog.pg_get_constraintdef(oid) AS condef "
    7285             :                               "FROM pg_catalog.pg_constraint "
    7286             :                               "WHERE conrelid = '%u'::pg_catalog.oid "
    7287             :                               "AND conparentid = 0 "
    7288             :                               "AND contype = 'f'",
    7289             :                               tbinfo->dobj.catId.oid);
    7290             :         else
    7291           0 :             appendPQExpBuffer(query,
    7292             :                               "SELECT tableoid, oid, conname, confrelid, 0 as conindid, "
    7293             :                               "pg_catalog.pg_get_constraintdef(oid) AS condef "
    7294             :                               "FROM pg_catalog.pg_constraint "
    7295             :                               "WHERE conrelid = '%u'::pg_catalog.oid "
    7296             :                               "AND contype = 'f'",
    7297             :                               tbinfo->dobj.catId.oid);
    7298         968 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7299             : 
    7300         968 :         ntups = PQntuples(res);
    7301             : 
    7302         968 :         i_contableoid = PQfnumber(res, "tableoid");
    7303         968 :         i_conoid = PQfnumber(res, "oid");
    7304         968 :         i_conname = PQfnumber(res, "conname");
    7305         968 :         i_confrelid = PQfnumber(res, "confrelid");
    7306         968 :         i_conindid = PQfnumber(res, "conindid");
    7307         968 :         i_condef = PQfnumber(res, "condef");
    7308             : 
    7309         968 :         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    7310             : 
    7311        1154 :         for (j = 0; j < ntups; j++)
    7312             :         {
    7313             :             TableInfo *reftable;
    7314             : 
    7315         186 :             constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    7316         186 :             constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7317         186 :             constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7318         186 :             AssignDumpId(&constrinfo[j].dobj);
    7319         186 :             constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7320         186 :             constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7321         186 :             constrinfo[j].contable = tbinfo;
    7322         186 :             constrinfo[j].condomain = NULL;
    7323         186 :             constrinfo[j].contype = 'f';
    7324         186 :             constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7325         186 :             constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    7326         186 :             constrinfo[j].conindex = 0;
    7327         186 :             constrinfo[j].condeferrable = false;
    7328         186 :             constrinfo[j].condeferred = false;
    7329         186 :             constrinfo[j].conislocal = true;
    7330         186 :             constrinfo[j].separate = true;
    7331             : 
    7332             :             /*
    7333             :              * Restoring an FK that points to a partitioned table requires
    7334             :              * that all partition indexes have been attached beforehand.
    7335             :              * Ensure that happens by making the constraint depend on each
    7336             :              * index partition attach object.
    7337             :              */
    7338         186 :             reftable = findTableByOid(constrinfo[j].confrelid);
    7339         186 :             if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    7340             :             {
    7341             :                 IndxInfo   *refidx;
    7342          18 :                 Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    7343             : 
    7344          18 :                 if (indexOid != InvalidOid)
    7345             :                 {
    7346          36 :                     for (int k = 0; k < reftable->numIndexes; k++)
    7347             :                     {
    7348             :                         SimplePtrListCell *cell;
    7349             : 
    7350             :                         /* not our index? */
    7351          18 :                         if (reftable->indexes[k].dobj.catId.oid != indexOid)
    7352           0 :                             continue;
    7353             : 
    7354          18 :                         refidx = &reftable->indexes[k];
    7355         102 :                         for (cell = refidx->partattaches.head; cell;
    7356          66 :                              cell = cell->next)
    7357          66 :                             addObjectDependency(&constrinfo[j].dobj,
    7358             :                                                 ((DumpableObject *)
    7359          66 :                                                  cell->ptr)->dumpId);
    7360          18 :                         break;
    7361             :                     }
    7362             :                 }
    7363             :             }
    7364             :         }
    7365             : 
    7366         968 :         PQclear(res);
    7367             :     }
    7368             : 
    7369         156 :     destroyPQExpBuffer(query);
    7370         156 : }
    7371             : 
    7372             : /*
    7373             :  * getDomainConstraints
    7374             :  *
    7375             :  * Get info about constraints on a domain.
    7376             :  */
    7377             : static void
    7378         144 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    7379             : {
    7380             :     int         i;
    7381             :     ConstraintInfo *constrinfo;
    7382             :     PQExpBuffer query;
    7383             :     PGresult   *res;
    7384             :     int         i_tableoid,
    7385             :                 i_oid,
    7386             :                 i_conname,
    7387             :                 i_consrc;
    7388             :     int         ntups;
    7389             : 
    7390         144 :     query = createPQExpBuffer();
    7391             : 
    7392         144 :     if (fout->remoteVersion >= 90100)
    7393         144 :         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
    7394             :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    7395             :                           "convalidated "
    7396             :                           "FROM pg_catalog.pg_constraint "
    7397             :                           "WHERE contypid = '%u'::pg_catalog.oid "
    7398             :                           "ORDER BY conname",
    7399             :                           tyinfo->dobj.catId.oid);
    7400             : 
    7401             :     else
    7402           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
    7403             :                           "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    7404             :                           "true as convalidated "
    7405             :                           "FROM pg_catalog.pg_constraint "
    7406             :                           "WHERE contypid = '%u'::pg_catalog.oid "
    7407             :                           "ORDER BY conname",
    7408             :                           tyinfo->dobj.catId.oid);
    7409             : 
    7410         144 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7411             : 
    7412         144 :     ntups = PQntuples(res);
    7413             : 
    7414         144 :     i_tableoid = PQfnumber(res, "tableoid");
    7415         144 :     i_oid = PQfnumber(res, "oid");
    7416         144 :     i_conname = PQfnumber(res, "conname");
    7417         144 :     i_consrc = PQfnumber(res, "consrc");
    7418             : 
    7419         144 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    7420             : 
    7421         144 :     tyinfo->nDomChecks = ntups;
    7422         144 :     tyinfo->domChecks = constrinfo;
    7423             : 
    7424         246 :     for (i = 0; i < ntups; i++)
    7425             :     {
    7426         102 :         bool        validated = PQgetvalue(res, i, 4)[0] == 't';
    7427             : 
    7428         102 :         constrinfo[i].dobj.objType = DO_CONSTRAINT;
    7429         102 :         constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7430         102 :         constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7431         102 :         AssignDumpId(&constrinfo[i].dobj);
    7432         102 :         constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    7433         102 :         constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
    7434         102 :         constrinfo[i].contable = NULL;
    7435         102 :         constrinfo[i].condomain = tyinfo;
    7436         102 :         constrinfo[i].contype = 'c';
    7437         102 :         constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    7438         102 :         constrinfo[i].confrelid = InvalidOid;
    7439         102 :         constrinfo[i].conindex = 0;
    7440         102 :         constrinfo[i].condeferrable = false;
    7441         102 :         constrinfo[i].condeferred = false;
    7442         102 :         constrinfo[i].conislocal = true;
    7443             : 
    7444         102 :         constrinfo[i].separate = !validated;
    7445             : 
    7446             :         /*
    7447             :          * Make the domain depend on the constraint, ensuring it won't be
    7448             :          * output till any constraint dependencies are OK.  If the constraint
    7449             :          * has not been validated, it's going to be dumped after the domain
    7450             :          * anyway, so this doesn't matter.
    7451             :          */
    7452         102 :         if (validated)
    7453         102 :             addObjectDependency(&tyinfo->dobj,
    7454         102 :                                 constrinfo[i].dobj.dumpId);
    7455             :     }
    7456             : 
    7457         144 :     PQclear(res);
    7458             : 
    7459         144 :     destroyPQExpBuffer(query);
    7460         144 : }
    7461             : 
    7462             : /*
    7463             :  * getRules
    7464             :  *    get basic information about every rule in the system
    7465             :  *
    7466             :  * numRules is set to the number of rules read in
    7467             :  */
    7468             : RuleInfo *
    7469         156 : getRules(Archive *fout, int *numRules)
    7470             : {
    7471             :     PGresult   *res;
    7472             :     int         ntups;
    7473             :     int         i;
    7474         156 :     PQExpBuffer query = createPQExpBuffer();
    7475             :     RuleInfo   *ruleinfo;
    7476             :     int         i_tableoid;
    7477             :     int         i_oid;
    7478             :     int         i_rulename;
    7479             :     int         i_ruletable;
    7480             :     int         i_ev_type;
    7481             :     int         i_is_instead;
    7482             :     int         i_ev_enabled;
    7483             : 
    7484         156 :     if (fout->remoteVersion >= 80300)
    7485             :     {
    7486         156 :         appendPQExpBufferStr(query, "SELECT "
    7487             :                              "tableoid, oid, rulename, "
    7488             :                              "ev_class AS ruletable, ev_type, is_instead, "
    7489             :                              "ev_enabled "
    7490             :                              "FROM pg_rewrite "
    7491             :                              "ORDER BY oid");
    7492             :     }
    7493             :     else
    7494             :     {
    7495           0 :         appendPQExpBufferStr(query, "SELECT "
    7496             :                              "tableoid, oid, rulename, "
    7497             :                              "ev_class AS ruletable, ev_type, is_instead, "
    7498             :                              "'O'::char AS ev_enabled "
    7499             :                              "FROM pg_rewrite "
    7500             :                              "ORDER BY oid");
    7501             :     }
    7502             : 
    7503         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7504             : 
    7505         156 :     ntups = PQntuples(res);
    7506             : 
    7507         156 :     *numRules = ntups;
    7508             : 
    7509         156 :     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    7510             : 
    7511         156 :     i_tableoid = PQfnumber(res, "tableoid");
    7512         156 :     i_oid = PQfnumber(res, "oid");
    7513         156 :     i_rulename = PQfnumber(res, "rulename");
    7514         156 :     i_ruletable = PQfnumber(res, "ruletable");
    7515         156 :     i_ev_type = PQfnumber(res, "ev_type");
    7516         156 :     i_is_instead = PQfnumber(res, "is_instead");
    7517         156 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    7518             : 
    7519       20780 :     for (i = 0; i < ntups; i++)
    7520             :     {
    7521             :         Oid         ruletableoid;
    7522             : 
    7523       20624 :         ruleinfo[i].dobj.objType = DO_RULE;
    7524       20624 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7525       20624 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7526       20624 :         AssignDumpId(&ruleinfo[i].dobj);
    7527       20624 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    7528       20624 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    7529       20624 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    7530       20624 :         if (ruleinfo[i].ruletable == NULL)
    7531           0 :             fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    7532             :                   ruletableoid, ruleinfo[i].dobj.catId.oid);
    7533       20624 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    7534       20624 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    7535       20624 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    7536       20624 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    7537       20624 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    7538       20624 :         if (ruleinfo[i].ruletable)
    7539             :         {
    7540             :             /*
    7541             :              * If the table is a view or materialized view, force its ON
    7542             :              * SELECT rule to be sorted before the view itself --- this
    7543             :              * ensures that any dependencies for the rule affect the table's
    7544             :              * positioning. Other rules are forced to appear after their
    7545             :              * table.
    7546             :              */
    7547       21240 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    7548       21072 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    7549       40564 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    7550             :             {
    7551       20108 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    7552       20108 :                                     ruleinfo[i].dobj.dumpId);
    7553             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    7554       20108 :                 ruleinfo[i].separate = false;
    7555             :             }
    7556             :             else
    7557             :             {
    7558         516 :                 addObjectDependency(&ruleinfo[i].dobj,
    7559         516 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    7560         516 :                 ruleinfo[i].separate = true;
    7561             :             }
    7562             :         }
    7563             :         else
    7564           0 :             ruleinfo[i].separate = true;
    7565             :     }
    7566             : 
    7567         156 :     PQclear(res);
    7568             : 
    7569         156 :     destroyPQExpBuffer(query);
    7570             : 
    7571         156 :     return ruleinfo;
    7572             : }
    7573             : 
    7574             : /*
    7575             :  * getTriggers
    7576             :  *    get information about every trigger on a dumpable table
    7577             :  *
    7578             :  * Note: trigger data is not returned directly to the caller, but it
    7579             :  * does get entered into the DumpableObject tables.
    7580             :  */
    7581             : void
    7582         156 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    7583             : {
    7584             :     int         i,
    7585             :                 j;
    7586         156 :     PQExpBuffer query = createPQExpBuffer();
    7587             :     PGresult   *res;
    7588             :     TriggerInfo *tginfo;
    7589             :     int         i_tableoid,
    7590             :                 i_oid,
    7591             :                 i_tgname,
    7592             :                 i_tgfname,
    7593             :                 i_tgtype,
    7594             :                 i_tgnargs,
    7595             :                 i_tgargs,
    7596             :                 i_tgisconstraint,
    7597             :                 i_tgconstrname,
    7598             :                 i_tgconstrrelid,
    7599             :                 i_tgconstrrelname,
    7600             :                 i_tgenabled,
    7601             :                 i_tgdeferrable,
    7602             :                 i_tginitdeferred,
    7603             :                 i_tgdef;
    7604             :     int         ntups;
    7605             : 
    7606       35736 :     for (i = 0; i < numTables; i++)
    7607             :     {
    7608       35580 :         TableInfo  *tbinfo = &tblinfo[i];
    7609             : 
    7610       36108 :         if (!tbinfo->hastriggers ||
    7611         528 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    7612       35080 :             continue;
    7613             : 
    7614         500 :         pg_log_info("reading triggers for table \"%s.%s\"",
    7615             :                     tbinfo->dobj.namespace->dobj.name,
    7616             :                     tbinfo->dobj.name);
    7617             : 
    7618         500 :         resetPQExpBuffer(query);
    7619         500 :         if (fout->remoteVersion >= 90000)
    7620             :         {
    7621             :             /*
    7622             :              * NB: think not to use pretty=true in pg_get_triggerdef.  It
    7623             :              * could result in non-forward-compatible dumps of WHEN clauses
    7624             :              * due to under-parenthesization.
    7625             :              */
    7626         500 :             appendPQExpBuffer(query,
    7627             :                               "SELECT tgname, "
    7628             :                               "tgfoid::pg_catalog.regproc AS tgfname, "
    7629             :                               "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
    7630             :                               "tgenabled, tableoid, oid "
    7631             :                               "FROM pg_catalog.pg_trigger t "
    7632             :                               "WHERE tgrelid = '%u'::pg_catalog.oid "
    7633             :                               "AND NOT tgisinternal",
    7634             :                               tbinfo->dobj.catId.oid);
    7635             :         }
    7636           0 :         else if (fout->remoteVersion >= 80300)
    7637             :         {
    7638             :             /*
    7639             :              * We ignore triggers that are tied to a foreign-key constraint
    7640             :              */
    7641           0 :             appendPQExpBuffer(query,
    7642             :                               "SELECT tgname, "
    7643             :                               "tgfoid::pg_catalog.regproc AS tgfname, "
    7644             :                               "tgtype, tgnargs, tgargs, tgenabled, "
    7645             :                               "tgisconstraint, tgconstrname, tgdeferrable, "
    7646             :                               "tgconstrrelid, tginitdeferred, tableoid, oid, "
    7647             :                               "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
    7648             :                               "FROM pg_catalog.pg_trigger t "
    7649             :                               "WHERE tgrelid = '%u'::pg_catalog.oid "
    7650             :                               "AND tgconstraint = 0",
    7651             :                               tbinfo->dobj.catId.oid);
    7652             :         }
    7653             :         else
    7654             :         {
    7655             :             /*
    7656             :              * We ignore triggers that are tied to a foreign-key constraint,
    7657             :              * but in these versions we have to grovel through pg_constraint
    7658             :              * to find out
    7659             :              */
    7660           0 :             appendPQExpBuffer(query,
    7661             :                               "SELECT tgname, "
    7662             :                               "tgfoid::pg_catalog.regproc AS tgfname, "
    7663             :                               "tgtype, tgnargs, tgargs, tgenabled, "
    7664             :                               "tgisconstraint, tgconstrname, tgdeferrable, "
    7665             :                               "tgconstrrelid, tginitdeferred, tableoid, oid, "
    7666             :                               "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
    7667             :                               "FROM pg_catalog.pg_trigger t "
    7668             :                               "WHERE tgrelid = '%u'::pg_catalog.oid "
    7669             :                               "AND (NOT tgisconstraint "
    7670             :                               " OR NOT EXISTS"
    7671             :                               "  (SELECT 1 FROM pg_catalog.pg_depend d "
    7672             :                               "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
    7673             :                               "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
    7674             :                               tbinfo->dobj.catId.oid);
    7675             :         }
    7676             : 
    7677         500 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7678             : 
    7679         500 :         ntups = PQntuples(res);
    7680             : 
    7681         500 :         i_tableoid = PQfnumber(res, "tableoid");
    7682         500 :         i_oid = PQfnumber(res, "oid");
    7683         500 :         i_tgname = PQfnumber(res, "tgname");
    7684         500 :         i_tgfname = PQfnumber(res, "tgfname");
    7685         500 :         i_tgtype = PQfnumber(res, "tgtype");
    7686         500 :         i_tgnargs = PQfnumber(res, "tgnargs");
    7687         500 :         i_tgargs = PQfnumber(res, "tgargs");
    7688         500 :         i_tgisconstraint = PQfnumber(res, "tgisconstraint");
    7689         500 :         i_tgconstrname = PQfnumber(res, "tgconstrname");
    7690         500 :         i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
    7691         500 :         i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
    7692         500 :         i_tgenabled = PQfnumber(res, "tgenabled");
    7693         500 :         i_tgdeferrable = PQfnumber(res, "tgdeferrable");
    7694         500 :         i_tginitdeferred = PQfnumber(res, "tginitdeferred");
    7695         500 :         i_tgdef = PQfnumber(res, "tgdef");
    7696             : 
    7697         500 :         tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    7698             : 
    7699         500 :         tbinfo->numTriggers = ntups;
    7700         500 :         tbinfo->triggers = tginfo;
    7701             : 
    7702         892 :         for (j = 0; j < ntups; j++)
    7703             :         {
    7704         392 :             tginfo[j].dobj.objType = DO_TRIGGER;
    7705         392 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    7706         392 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    7707         392 :             AssignDumpId(&tginfo[j].dobj);
    7708         392 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    7709         392 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7710         392 :             tginfo[j].tgtable = tbinfo;
    7711         392 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    7712         392 :             if (i_tgdef >= 0)
    7713             :             {
    7714         392 :                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    7715             : 
    7716             :                 /* remaining fields are not valid if we have tgdef */
    7717         392 :                 tginfo[j].tgfname = NULL;
    7718         392 :                 tginfo[j].tgtype = 0;
    7719         392 :                 tginfo[j].tgnargs = 0;
    7720         392 :                 tginfo[j].tgargs = NULL;
    7721         392 :                 tginfo[j].tgisconstraint = false;
    7722         392 :                 tginfo[j].tgdeferrable = false;
    7723         392 :                 tginfo[j].tginitdeferred = false;
    7724         392 :                 tginfo[j].tgconstrname = NULL;
    7725         392 :                 tginfo[j].tgconstrrelid = InvalidOid;
    7726         392 :                 tginfo[j].tgconstrrelname = NULL;
    7727             :             }
    7728             :             else
    7729             :             {
    7730           0 :                 tginfo[j].tgdef = NULL;
    7731             : 
    7732           0 :                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
    7733           0 :                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
    7734           0 :                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
    7735           0 :                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
    7736           0 :                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
    7737           0 :                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
    7738           0 :                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
    7739             : 
    7740           0 :                 if (tginfo[j].tgisconstraint)
    7741             :                 {
    7742           0 :                     tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
    7743           0 :                     tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
    7744           0 :                     if (OidIsValid(tginfo[j].tgconstrrelid))
    7745             :                     {
    7746           0 :                         if (PQgetisnull(res, j, i_tgconstrrelname))
    7747           0 :                             fatal("query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)",
    7748             :                                   tginfo[j].dobj.name,
    7749             :                                   tbinfo->dobj.name,
    7750             :                                   tginfo[j].tgconstrrelid);
    7751           0 :                         tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
    7752             :                     }
    7753             :                     else
    7754           0 :                         tginfo[j].tgconstrrelname = NULL;
    7755             :                 }
    7756             :                 else
    7757             :                 {
    7758           0 :                     tginfo[j].tgconstrname = NULL;
    7759           0 :                     tginfo[j].tgconstrrelid = InvalidOid;
    7760           0 :                     tginfo[j].tgconstrrelname = NULL;
    7761             :                 }
    7762             :             }
    7763             :         }
    7764             : 
    7765         500 :         PQclear(res);
    7766             :     }
    7767             : 
    7768         156 :     destroyPQExpBuffer(query);
    7769         156 : }
    7770             : 
    7771             : /*
    7772             :  * getEventTriggers
    7773             :  *    get information about event triggers
    7774             :  */
    7775             : EventTriggerInfo *
    7776         156 : getEventTriggers(Archive *fout, int *numEventTriggers)
    7777             : {
    7778             :     int         i;
    7779             :     PQExpBuffer query;
    7780             :     PGresult   *res;
    7781             :     EventTriggerInfo *evtinfo;
    7782             :     int         i_tableoid,
    7783             :                 i_oid,
    7784             :                 i_evtname,
    7785             :                 i_evtevent,
    7786             :                 i_evtowner,
    7787             :                 i_evttags,
    7788             :                 i_evtfname,
    7789             :                 i_evtenabled;
    7790             :     int         ntups;
    7791             : 
    7792             :     /* Before 9.3, there are no event triggers */
    7793         156 :     if (fout->remoteVersion < 90300)
    7794             :     {
    7795           0 :         *numEventTriggers = 0;
    7796           0 :         return NULL;
    7797             :     }
    7798             : 
    7799         156 :     query = createPQExpBuffer();
    7800             : 
    7801         156 :     appendPQExpBuffer(query,
    7802             :                       "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    7803             :                       "evtevent, (%s evtowner) AS evtowner, "
    7804             :                       "array_to_string(array("
    7805             :                       "select quote_literal(x) "
    7806             :                       " from unnest(evttags) as t(x)), ', ') as evttags, "
    7807             :                       "e.evtfoid::regproc as evtfname "
    7808             :                       "FROM pg_event_trigger e "
    7809             :                       "ORDER BY e.oid",
    7810             :                       username_subquery);
    7811             : 
    7812         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7813             : 
    7814         156 :     ntups = PQntuples(res);
    7815             : 
    7816         156 :     *numEventTriggers = ntups;
    7817             : 
    7818         156 :     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    7819             : 
    7820         156 :     i_tableoid = PQfnumber(res, "tableoid");
    7821         156 :     i_oid = PQfnumber(res, "oid");
    7822         156 :     i_evtname = PQfnumber(res, "evtname");
    7823         156 :     i_evtevent = PQfnumber(res, "evtevent");
    7824         156 :     i_evtowner = PQfnumber(res, "evtowner");
    7825         156 :     i_evttags = PQfnumber(res, "evttags");
    7826         156 :     i_evtfname = PQfnumber(res, "evtfname");
    7827         156 :     i_evtenabled = PQfnumber(res, "evtenabled");
    7828             : 
    7829         214 :     for (i = 0; i < ntups; i++)
    7830             :     {
    7831          58 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    7832          58 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7833          58 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7834          58 :         AssignDumpId(&evtinfo[i].dobj);
    7835          58 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    7836          58 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    7837          58 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    7838          58 :         evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
    7839          58 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    7840          58 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    7841          58 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    7842             : 
    7843             :         /* Decide whether we want to dump it */
    7844          58 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    7845             : 
    7846             :         /* Event Triggers do not currently have ACLs. */
    7847          58 :         evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    7848             :     }
    7849             : 
    7850         156 :     PQclear(res);
    7851             : 
    7852         156 :     destroyPQExpBuffer(query);
    7853             : 
    7854         156 :     return evtinfo;
    7855             : }
    7856             : 
    7857             : /*
    7858             :  * getProcLangs
    7859             :  *    get basic information about every procedural language in the system
    7860             :  *
    7861             :  * numProcLangs is set to the number of langs read in
    7862             :  *
    7863             :  * NB: this must run after getFuncs() because we assume we can do
    7864             :  * findFuncByOid().
    7865             :  */
    7866             : ProcLangInfo *
    7867         156 : getProcLangs(Archive *fout, int *numProcLangs)
    7868             : {
    7869         156 :     DumpOptions *dopt = fout->dopt;
    7870             :     PGresult   *res;
    7871             :     int         ntups;
    7872             :     int         i;
    7873         156 :     PQExpBuffer query = createPQExpBuffer();
    7874             :     ProcLangInfo *planginfo;
    7875             :     int         i_tableoid;
    7876             :     int         i_oid;
    7877             :     int         i_lanname;
    7878             :     int         i_lanpltrusted;
    7879             :     int         i_lanplcallfoid;
    7880             :     int         i_laninline;
    7881             :     int         i_lanvalidator;
    7882             :     int         i_lanacl;
    7883             :     int         i_rlanacl;
    7884             :     int         i_initlanacl;
    7885             :     int         i_initrlanacl;
    7886             :     int         i_lanowner;
    7887             : 
    7888         156 :     if (fout->remoteVersion >= 90600)
    7889             :     {
    7890         156 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    7891         156 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    7892         156 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    7893         156 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    7894             : 
    7895         156 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    7896             :                         initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
    7897         156 :                         dopt->binary_upgrade);
    7898             : 
    7899             :         /* pg_language has a laninline column */
    7900         156 :         appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
    7901             :                           "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
    7902             :                           "l.laninline, l.lanvalidator, "
    7903             :                           "%s AS lanacl, "
    7904             :                           "%s AS rlanacl, "
    7905             :                           "%s AS initlanacl, "
    7906             :                           "%s AS initrlanacl, "
    7907             :                           "(%s l.lanowner) AS lanowner "
    7908             :                           "FROM pg_language l "
    7909             :                           "LEFT JOIN pg_init_privs pip ON "
    7910             :                           "(l.oid = pip.objoid "
    7911             :                           "AND pip.classoid = 'pg_language'::regclass "
    7912             :                           "AND pip.objsubid = 0) "
    7913             :                           "WHERE l.lanispl "
    7914             :                           "ORDER BY l.oid",
    7915             :                           acl_subquery->data,
    7916             :                           racl_subquery->data,
    7917             :                           initacl_subquery->data,
    7918             :                           initracl_subquery->data,
    7919             :                           username_subquery);
    7920             : 
    7921         156 :         destroyPQExpBuffer(acl_subquery);
    7922         156 :         destroyPQExpBuffer(racl_subquery);
    7923         156 :         destroyPQExpBuffer(initacl_subquery);
    7924         156 :         destroyPQExpBuffer(initracl_subquery);
    7925             :     }
    7926           0 :     else if (fout->remoteVersion >= 90000)
    7927             :     {
    7928             :         /* pg_language has a laninline column */
    7929           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, "
    7930             :                           "lanname, lanpltrusted, lanplcallfoid, "
    7931             :                           "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
    7932             :                           "NULL AS initlanacl, NULL AS initrlanacl, "
    7933             :                           "(%s lanowner) AS lanowner "
    7934             :                           "FROM pg_language "
    7935             :                           "WHERE lanispl "
    7936             :                           "ORDER BY oid",
    7937             :                           username_subquery);
    7938             :     }
    7939           0 :     else if (fout->remoteVersion >= 80300)
    7940             :     {
    7941             :         /* pg_language has a lanowner column */
    7942           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, "
    7943             :                           "lanname, lanpltrusted, lanplcallfoid, "
    7944             :                           "0 AS laninline, lanvalidator, lanacl, "
    7945             :                           "NULL AS rlanacl, "
    7946             :                           "NULL AS initlanacl, NULL AS initrlanacl, "
    7947             :                           "(%s lanowner) AS lanowner "
    7948             :                           "FROM pg_language "
    7949             :                           "WHERE lanispl "
    7950             :                           "ORDER BY oid",
    7951             :                           username_subquery);
    7952             :     }
    7953           0 :     else if (fout->remoteVersion >= 80100)
    7954             :     {
    7955             :         /* Languages are owned by the bootstrap superuser, OID 10 */
    7956           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, "
    7957             :                           "lanname, lanpltrusted, lanplcallfoid, "
    7958             :                           "0 AS laninline, lanvalidator, lanacl, "
    7959             :                           "NULL AS rlanacl, "
    7960             :                           "NULL AS initlanacl, NULL AS initrlanacl, "
    7961             :                           "(%s '10') AS lanowner "
    7962             :                           "FROM pg_language "
    7963             :                           "WHERE lanispl "
    7964             :                           "ORDER BY oid",
    7965             :                           username_subquery);
    7966             :     }
    7967             :     else
    7968             :     {
    7969             :         /* Languages are owned by the bootstrap superuser, sysid 1 */
    7970           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, "
    7971             :                           "lanname, lanpltrusted, lanplcallfoid, "
    7972             :                           "0 AS laninline, lanvalidator, lanacl, "
    7973             :                           "NULL AS rlanacl, "
    7974             :                           "NULL AS initlanacl, NULL AS initrlanacl, "
    7975             :                           "(%s '1') AS lanowner "
    7976             :                           "FROM pg_language "
    7977             :                           "WHERE lanispl "
    7978             :                           "ORDER BY oid",
    7979             :                           username_subquery);
    7980             :     }
    7981             : 
    7982         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7983             : 
    7984         156 :     ntups = PQntuples(res);
    7985             : 
    7986         156 :     *numProcLangs = ntups;
    7987             : 
    7988         156 :     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    7989             : 
    7990         156 :     i_tableoid = PQfnumber(res, "tableoid");
    7991         156 :     i_oid = PQfnumber(res, "oid");
    7992         156 :     i_lanname = PQfnumber(res, "lanname");
    7993         156 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    7994         156 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    7995         156 :     i_laninline = PQfnumber(res, "laninline");
    7996         156 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    7997         156 :     i_lanacl = PQfnumber(res, "lanacl");
    7998         156 :     i_rlanacl = PQfnumber(res, "rlanacl");
    7999         156 :     i_initlanacl = PQfnumber(res, "initlanacl");
    8000         156 :     i_initrlanacl = PQfnumber(res, "initrlanacl");
    8001         156 :     i_lanowner = PQfnumber(res, "lanowner");
    8002             : 
    8003         370 :     for (i = 0; i < ntups; i++)
    8004             :     {
    8005         214 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8006         214 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8007         214 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8008         214 :         AssignDumpId(&planginfo[i].dobj);
    8009             : 
    8010         214 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8011         214 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8012         214 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8013         214 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8014         214 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8015         214 :         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8016         214 :         planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
    8017         214 :         planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
    8018         214 :         planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
    8019         214 :         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
    8020             : 
    8021             :         /* Decide whether we want to dump it */
    8022         214 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8023             : 
    8024             :         /* Do not try to dump ACL if no ACL exists. */
    8025         370 :         if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
    8026         312 :             PQgetisnull(res, i, i_initlanacl) &&
    8027         156 :             PQgetisnull(res, i, i_initrlanacl))
    8028         156 :             planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    8029             :     }
    8030             : 
    8031         156 :     PQclear(res);
    8032             : 
    8033         156 :     destroyPQExpBuffer(query);
    8034             : 
    8035         156 :     return planginfo;
    8036             : }
    8037             : 
    8038             : /*
    8039             :  * getCasts
    8040             :  *    get basic information about every cast in the system
    8041             :  *
    8042             :  * numCasts is set to the number of casts read in
    8043             :  */
    8044             : CastInfo *
    8045         156 : getCasts(Archive *fout, int *numCasts)
    8046             : {
    8047             :     PGresult   *res;
    8048             :     int         ntups;
    8049             :     int         i;
    8050         156 :     PQExpBuffer query = createPQExpBuffer();
    8051             :     CastInfo   *castinfo;
    8052             :     int         i_tableoid;
    8053             :     int         i_oid;
    8054             :     int         i_castsource;
    8055             :     int         i_casttarget;
    8056             :     int         i_castfunc;
    8057             :     int         i_castcontext;
    8058             :     int         i_castmethod;
    8059             : 
    8060         156 :     if (fout->remoteVersion >= 80400)
    8061             :     {
    8062         156 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8063             :                              "castsource, casttarget, castfunc, castcontext, "
    8064             :                              "castmethod "
    8065             :                              "FROM pg_cast ORDER BY 3,4");
    8066             :     }
    8067             :     else
    8068             :     {
    8069           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8070             :                              "castsource, casttarget, castfunc, castcontext, "
    8071             :                              "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
    8072             :                              "FROM pg_cast ORDER BY 3,4");
    8073             :     }
    8074             : 
    8075         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8076             : 
    8077         156 :     ntups = PQntuples(res);
    8078             : 
    8079         156 :     *numCasts = ntups;
    8080             : 
    8081         156 :     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    8082             : 
    8083         156 :     i_tableoid = PQfnumber(res, "tableoid");
    8084         156 :     i_oid = PQfnumber(res, "oid");
    8085         156 :     i_castsource = PQfnumber(res, "castsource");
    8086         156 :     i_casttarget = PQfnumber(res, "casttarget");
    8087         156 :     i_castfunc = PQfnumber(res, "castfunc");
    8088         156 :     i_castcontext = PQfnumber(res, "castcontext");
    8089         156 :     i_castmethod = PQfnumber(res, "castmethod");
    8090             : 
    8091       33946 :     for (i = 0; i < ntups; i++)
    8092             :     {
    8093             :         PQExpBufferData namebuf;
    8094             :         TypeInfo   *sTypeInfo;
    8095             :         TypeInfo   *tTypeInfo;
    8096             : 
    8097       33790 :         castinfo[i].dobj.objType = DO_CAST;
    8098       33790 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8099       33790 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8100       33790 :         AssignDumpId(&castinfo[i].dobj);
    8101       33790 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    8102       33790 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    8103       33790 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    8104       33790 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    8105       33790 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    8106             : 
    8107             :         /*
    8108             :          * Try to name cast as concatenation of typnames.  This is only used
    8109             :          * for purposes of sorting.  If we fail to find either type, the name
    8110             :          * will be an empty string.
    8111             :          */
    8112       33790 :         initPQExpBuffer(&namebuf);
    8113       33790 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    8114       33790 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    8115       33790 :         if (sTypeInfo && tTypeInfo)
    8116       33790 :             appendPQExpBuffer(&namebuf, "%s %s",
    8117             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    8118       33790 :         castinfo[i].dobj.name = namebuf.data;
    8119             : 
    8120             :         /* Decide whether we want to dump it */
    8121       33790 :         selectDumpableCast(&(castinfo[i]), fout);
    8122             : 
    8123             :         /* Casts do not currently have ACLs. */
    8124       33790 :         castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    8125             :     }
    8126             : 
    8127         156 :     PQclear(res);
    8128             : 
    8129         156 :     destroyPQExpBuffer(query);
    8130             : 
    8131         156 :     return castinfo;
    8132             : }
    8133             : 
    8134             : static char *
    8135         112 : get_language_name(Archive *fout, Oid langid)
    8136             : {
    8137             :     PQExpBuffer query;
    8138             :     PGresult   *res;
    8139             :     char       *lanname;
    8140             : 
    8141         112 :     query = createPQExpBuffer();
    8142         112 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    8143         112 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    8144         112 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    8145         112 :     destroyPQExpBuffer(query);
    8146         112 :     PQclear(res);
    8147             : 
    8148         112 :     return lanname;
    8149             : }
    8150             : 
    8151             : /*
    8152             :  * getTransforms
    8153             :  *    get basic information about every transform in the system
    8154             :  *
    8155             :  * numTransforms is set to the number of transforms read in
    8156             :  */
    8157             : TransformInfo *
    8158         156 : getTransforms(Archive *fout, int *numTransforms)
    8159             : {
    8160             :     PGresult   *res;
    8161             :     int         ntups;
    8162             :     int         i;
    8163             :     PQExpBuffer query;
    8164             :     TransformInfo *transforminfo;
    8165             :     int         i_tableoid;
    8166             :     int         i_oid;
    8167             :     int         i_trftype;
    8168             :     int         i_trflang;
    8169             :     int         i_trffromsql;
    8170             :     int         i_trftosql;
    8171             : 
    8172             :     /* Transforms didn't exist pre-9.5 */
    8173         156 :     if (fout->remoteVersion < 90500)
    8174             :     {
    8175           0 :         *numTransforms = 0;
    8176           0 :         return NULL;
    8177             :     }
    8178             : 
    8179         156 :     query = createPQExpBuffer();
    8180             : 
    8181         156 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8182             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    8183             :                          "FROM pg_transform "
    8184             :                          "ORDER BY 3,4");
    8185             : 
    8186         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8187             : 
    8188         156 :     ntups = PQntuples(res);
    8189             : 
    8190         156 :     *numTransforms = ntups;
    8191             : 
    8192         156 :     transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    8193             : 
    8194         156 :     i_tableoid = PQfnumber(res, "tableoid");
    8195         156 :     i_oid = PQfnumber(res, "oid");
    8196         156 :     i_trftype = PQfnumber(res, "trftype");
    8197         156 :     i_trflang = PQfnumber(res, "trflang");
    8198         156 :     i_trffromsql = PQfnumber(res, "trffromsql");
    8199         156 :     i_trftosql = PQfnumber(res, "trftosql");
    8200             : 
    8201         220 :     for (i = 0; i < ntups; i++)
    8202             :     {
    8203             :         PQExpBufferData namebuf;
    8204             :         TypeInfo   *typeInfo;
    8205             :         char       *lanname;
    8206             : 
    8207          64 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    8208          64 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8209          64 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8210          64 :         AssignDumpId(&transforminfo[i].dobj);
    8211          64 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    8212          64 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    8213          64 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    8214          64 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    8215             : 
    8216             :         /*
    8217             :          * Try to name transform as concatenation of type and language name.
    8218             :          * This is only used for purposes of sorting.  If we fail to find
    8219             :          * either, the name will be an empty string.
    8220             :          */
    8221          64 :         initPQExpBuffer(&namebuf);
    8222          64 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    8223          64 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    8224          64 :         if (typeInfo && lanname)
    8225          64 :             appendPQExpBuffer(&namebuf, "%s %s",
    8226             :                               typeInfo->dobj.name, lanname);
    8227          64 :         transforminfo[i].dobj.name = namebuf.data;
    8228          64 :         free(lanname);
    8229             : 
    8230             :         /* Decide whether we want to dump it */
    8231          64 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    8232             :     }
    8233             : 
    8234         156 :     PQclear(res);
    8235             : 
    8236         156 :     destroyPQExpBuffer(query);
    8237             : 
    8238         156 :     return transforminfo;
    8239             : }
    8240             : 
    8241             : /*
    8242             :  * getTableAttrs -
    8243             :  *    for each interesting table, read info about its attributes
    8244             :  *    (names, types, default values, CHECK constraints, etc)
    8245             :  *
    8246             :  * This is implemented in a very inefficient way right now, looping
    8247             :  * through the tblinfo and doing a join per table to find the attrs and their
    8248             :  * types.  However, because we want type names and so forth to be named
    8249             :  * relative to the schema of each table, we couldn't do it in just one
    8250             :  * query.  (Maybe one query per schema?)
    8251             :  *
    8252             :  *  modifies tblinfo
    8253             :  */
    8254             : void
    8255         156 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    8256             : {
    8257         156 :     DumpOptions *dopt = fout->dopt;
    8258             :     int         i,
    8259             :                 j;
    8260         156 :     PQExpBuffer q = createPQExpBuffer();
    8261             :     int         i_attnum;
    8262             :     int         i_attname;
    8263             :     int         i_atttypname;
    8264             :     int         i_atttypmod;
    8265             :     int         i_attstattarget;
    8266             :     int         i_attstorage;
    8267             :     int         i_typstorage;
    8268             :     int         i_attnotnull;
    8269             :     int         i_atthasdef;
    8270             :     int         i_attidentity;
    8271             :     int         i_attgenerated;
    8272             :     int         i_attisdropped;
    8273             :     int         i_attlen;
    8274             :     int         i_attalign;
    8275             :     int         i_attislocal;
    8276             :     int         i_attoptions;
    8277             :     int         i_attcollation;
    8278             :     int         i_attfdwoptions;
    8279             :     int         i_attmissingval;
    8280             :     PGresult   *res;
    8281             :     int         ntups;
    8282             :     bool        hasdefaults;
    8283             : 
    8284       35736 :     for (i = 0; i < numTables; i++)
    8285             :     {
    8286       35580 :         TableInfo  *tbinfo = &tblinfo[i];
    8287             : 
    8288             :         /* Don't bother to collect info for sequences */
    8289       35580 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    8290         530 :             continue;
    8291             : 
    8292             :         /* Don't bother with uninteresting tables, either */
    8293       35050 :         if (!tbinfo->interesting)
    8294       30172 :             continue;
    8295             : 
    8296             :         /* find all the user attributes and their types */
    8297             : 
    8298             :         /*
    8299             :          * we must read the attribute names in attribute number order! because
    8300             :          * we will use the attnum to index into the attnames array later.
    8301             :          */
    8302        4878 :         pg_log_info("finding the columns and types of table \"%s.%s\"",
    8303             :                     tbinfo->dobj.namespace->dobj.name,
    8304             :                     tbinfo->dobj.name);
    8305             : 
    8306        4878 :         resetPQExpBuffer(q);
    8307             : 
    8308        4878 :         appendPQExpBufferStr(q,
    8309             :                              "SELECT\n"
    8310             :                              "a.attnum,\n"
    8311             :                              "a.attname,\n"
    8312             :                              "a.atttypmod,\n"
    8313             :                              "a.attstattarget,\n"
    8314             :                              "a.attstorage,\n"
    8315             :                              "t.typstorage,\n"
    8316             :                              "a.attnotnull,\n"
    8317             :                              "a.atthasdef,\n"
    8318             :                              "a.attisdropped,\n"
    8319             :                              "a.attlen,\n"
    8320             :                              "a.attalign,\n"
    8321             :                              "a.attislocal,\n"
    8322             :                              "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
    8323             : 
    8324        4878 :         if (fout->remoteVersion >= 120000)
    8325        4878 :             appendPQExpBufferStr(q,
    8326             :                                  "a.attgenerated,\n");
    8327             :         else
    8328           0 :             appendPQExpBufferStr(q,
    8329             :                                  "'' AS attgenerated,\n");
    8330             : 
    8331        4878 :         if (fout->remoteVersion >= 110000)
    8332        4878 :             appendPQExpBufferStr(q,
    8333             :                                  "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    8334             :                                  "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    8335             :         else
    8336           0 :             appendPQExpBufferStr(q,
    8337             :                                  "NULL AS attmissingval,\n");
    8338             : 
    8339        4878 :         if (fout->remoteVersion >= 100000)
    8340        4878 :             appendPQExpBufferStr(q,
    8341             :                                  "a.attidentity,\n");
    8342             :         else
    8343           0 :             appendPQExpBufferStr(q,
    8344             :                                  "'' AS attidentity,\n");
    8345             : 
    8346        4878 :         if (fout->remoteVersion >= 90200)
    8347        4878 :             appendPQExpBufferStr(q,
    8348             :                                  "pg_catalog.array_to_string(ARRAY("
    8349             :                                  "SELECT pg_catalog.quote_ident(option_name) || "
    8350             :                                  "' ' || pg_catalog.quote_literal(option_value) "
    8351             :                                  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    8352             :                                  "ORDER BY option_name"
    8353             :                                  "), E',\n    ') AS attfdwoptions,\n");
    8354             :         else
    8355           0 :             appendPQExpBufferStr(q,
    8356             :                                  "'' AS attfdwoptions,\n");
    8357             : 
    8358        4878 :         if (fout->remoteVersion >= 90100)
    8359             :         {
    8360             :             /*
    8361             :              * Since we only want to dump COLLATE clauses for attributes whose
    8362             :              * collation is different from their type's default, we use a CASE
    8363             :              * here to suppress uninteresting attcollations cheaply.
    8364             :              */
    8365        4878 :             appendPQExpBufferStr(q,
    8366             :                                  "CASE WHEN a.attcollation <> t.typcollation "
    8367             :                                  "THEN a.attcollation ELSE 0 END AS attcollation,\n");
    8368             :         }
    8369             :         else
    8370           0 :             appendPQExpBufferStr(q,
    8371             :                                  "0 AS attcollation,\n");
    8372             : 
    8373        4878 :         if (fout->remoteVersion >= 90000)
    8374        4878 :             appendPQExpBufferStr(q,
    8375             :                                  "array_to_string(a.attoptions, ', ') AS attoptions\n");
    8376             :         else
    8377           0 :             appendPQExpBufferStr(q,
    8378             :                                  "'' AS attoptions\n");
    8379             : 
    8380             :         /* need left join here to not fail on dropped columns ... */
    8381        4878 :         appendPQExpBuffer(q,
    8382             :                           "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
    8383             :                           "ON a.atttypid = t.oid\n"
    8384             :                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
    8385             :                           "AND a.attnum > 0::pg_catalog.int2\n"
    8386             :                           "ORDER BY a.attnum",
    8387             :                           tbinfo->dobj.catId.oid);
    8388             : 
    8389        4878 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    8390             : 
    8391        4878 :         ntups = PQntuples(res);
    8392             : 
    8393        4878 :         i_attnum = PQfnumber(res, "attnum");
    8394        4878 :         i_attname = PQfnumber(res, "attname");
    8395        4878 :         i_atttypname = PQfnumber(res, "atttypname");
    8396        4878 :         i_atttypmod = PQfnumber(res, "atttypmod");
    8397        4878 :         i_attstattarget = PQfnumber(res, "attstattarget");
    8398        4878 :         i_attstorage = PQfnumber(res, "attstorage");
    8399        4878 :         i_typstorage = PQfnumber(res, "typstorage");
    8400        4878 :         i_attnotnull = PQfnumber(res, "attnotnull");
    8401        4878 :         i_atthasdef = PQfnumber(res, "atthasdef");
    8402        4878 :         i_attidentity = PQfnumber(res, "attidentity");
    8403        4878 :         i_attgenerated = PQfnumber(res, "attgenerated");
    8404        4878 :         i_attisdropped = PQfnumber(res, "attisdropped");
    8405        4878 :         i_attlen = PQfnumber(res, "attlen");
    8406        4878 :         i_attalign = PQfnumber(res, "attalign");
    8407        4878 :         i_attislocal = PQfnumber(res, "attislocal");
    8408        4878 :         i_attoptions = PQfnumber(res, "attoptions");
    8409        4878 :         i_attcollation = PQfnumber(res, "attcollation");
    8410        4878 :         i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    8411        4878 :         i_attmissingval = PQfnumber(res, "attmissingval");
    8412             : 
    8413        4878 :         tbinfo->numatts = ntups;
    8414        4878 :         tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
    8415        4878 :         tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
    8416        4878 :         tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
    8417        4878 :         tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
    8418        4878 :         tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
    8419        4878 :         tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
    8420        4878 :         tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
    8421        4878 :         tbinfo->attgenerated = (char *) pg_malloc(ntups * sizeof(char));
    8422        4878 :         tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
    8423        4878 :         tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
    8424        4878 :         tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
    8425        4878 :         tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
    8426        4878 :         tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
    8427        4878 :         tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
    8428        4878 :         tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
    8429        4878 :         tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
    8430        4878 :         tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
    8431        4878 :         tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
    8432        4878 :         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
    8433        4878 :         hasdefaults = false;
    8434             : 
    8435       24326 :         for (j = 0; j < ntups; j++)
    8436             :         {
    8437       19448 :             if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
    8438           0 :                 fatal("invalid column numbering in table \"%s\"",
    8439             :                       tbinfo->dobj.name);
    8440       19448 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
    8441       19448 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
    8442       19448 :             tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
    8443       19448 :             tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
    8444       19448 :             tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
    8445       19448 :             tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
    8446       19448 :             tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
    8447       19448 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, j, i_attgenerated));
    8448       19448 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    8449       19448 :             tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
    8450       19448 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
    8451       19448 :             tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
    8452       19448 :             tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
    8453       19448 :             tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
    8454       19448 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
    8455       19448 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
    8456       19448 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
    8457       19448 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
    8458       19448 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    8459       19448 :             if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
    8460         644 :                 hasdefaults = true;
    8461             :             /* these flags will be set in flagInhAttrs() */
    8462       19448 :             tbinfo->inhNotNull[j] = false;
    8463             :         }
    8464             : 
    8465        4878 :         PQclear(res);
    8466             : 
    8467             :         /*
    8468             :          * Get info about column defaults
    8469             :          */
    8470        4878 :         if (hasdefaults)
    8471             :         {
    8472             :             AttrDefInfo *attrdefs;
    8473             :             int         numDefaults;
    8474             : 
    8475         534 :             pg_log_info("finding default expressions of table \"%s.%s\"",
    8476             :                         tbinfo->dobj.namespace->dobj.name,
    8477             :                         tbinfo->dobj.name);
    8478             : 
    8479         534 :             printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
    8480             :                               "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
    8481             :                               "FROM pg_catalog.pg_attrdef "
    8482             :                               "WHERE adrelid = '%u'::pg_catalog.oid",
    8483             :                               tbinfo->dobj.catId.oid);
    8484             : 
    8485         534 :             res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    8486             : 
    8487         534 :             numDefaults = PQntuples(res);
    8488         534 :             attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    8489             : 
    8490        1178 :             for (j = 0; j < numDefaults; j++)
    8491             :             {
    8492             :                 int         adnum;
    8493             : 
    8494         644 :                 adnum = atoi(PQgetvalue(res, j, 2));
    8495             : 
    8496         644 :                 if (adnum <= 0 || adnum > ntups)
    8497           0 :                     fatal("invalid adnum value %d for table \"%s\"",
    8498             :                           adnum, tbinfo->dobj.name);
    8499             : 
    8500             :                 /*
    8501             :                  * dropped columns shouldn't have defaults, but just in case,
    8502             :                  * ignore 'em
    8503             :                  */
    8504         644 :                 if (tbinfo->attisdropped[adnum - 1])
    8505           0 :                     continue;
    8506             : 
    8507         644 :                 attrdefs[j].dobj.objType = DO_ATTRDEF;
    8508         644 :                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
    8509         644 :                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
    8510         644 :                 AssignDumpId(&attrdefs[j].dobj);
    8511         644 :                 attrdefs[j].adtable = tbinfo;
    8512         644 :                 attrdefs[j].adnum = adnum;
    8513         644 :                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
    8514             : 
    8515         644 :                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    8516         644 :                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    8517             : 
    8518         644 :                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    8519             : 
    8520             :                 /*
    8521             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    8522             :                  * TABLE commands.  Defaults on regular tables are dumped as
    8523             :                  * part of the CREATE TABLE if possible, which it won't be if
    8524             :                  * the column is not going to be emitted explicitly.
    8525             :                  */
    8526         644 :                 if (tbinfo->relkind == RELKIND_VIEW)
    8527             :                 {
    8528          48 :                     attrdefs[j].separate = true;
    8529             :                 }
    8530         596 :                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    8531             :                 {
    8532             :                     /* column will be suppressed, print default separately */
    8533           8 :                     attrdefs[j].separate = true;
    8534             :                 }
    8535             :                 else
    8536             :                 {
    8537         588 :                     attrdefs[j].separate = false;
    8538             : 
    8539             :                     /*
    8540             :                      * Mark the default as needing to appear before the table,
    8541             :                      * so that any dependencies it has must be emitted before
    8542             :                      * the CREATE TABLE.  If this is not possible, we'll
    8543             :                      * change to "separate" mode while sorting dependencies.
    8544             :                      */
    8545         588 :                     addObjectDependency(&tbinfo->dobj,
    8546         588 :                                         attrdefs[j].dobj.dumpId);
    8547             :                 }
    8548             : 
    8549         644 :                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    8550             :             }
    8551         534 :             PQclear(res);
    8552             :         }
    8553             : 
    8554             :         /*
    8555             :          * Get info about table CHECK constraints
    8556             :          */
    8557        4878 :         if (tbinfo->ncheck > 0)
    8558             :         {
    8559             :             ConstraintInfo *constrs;
    8560             :             int         numConstrs;
    8561             : 
    8562         370 :             pg_log_info("finding check constraints for table \"%s.%s\"",
    8563             :                         tbinfo->dobj.namespace->dobj.name,
    8564             :                         tbinfo->dobj.name);
    8565             : 
    8566         370 :             resetPQExpBuffer(q);
    8567         370 :             if (fout->remoteVersion >= 90200)
    8568             :             {
    8569             :                 /*
    8570             :                  * convalidated is new in 9.2 (actually, it is there in 9.1,
    8571             :                  * but it wasn't ever false for check constraints until 9.2).
    8572             :                  */
    8573         370 :                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
    8574             :                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8575             :                                   "conislocal, convalidated "
    8576             :                                   "FROM pg_catalog.pg_constraint "
    8577             :                                   "WHERE conrelid = '%u'::pg_catalog.oid "
    8578             :                                   "   AND contype = 'c' "
    8579             :                                   "ORDER BY conname",
    8580             :                                   tbinfo->dobj.catId.oid);
    8581             :             }
    8582           0 :             else if (fout->remoteVersion >= 80400)
    8583             :             {
    8584             :                 /* conislocal is new in 8.4 */
    8585           0 :                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
    8586             :                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8587             :                                   "conislocal, true AS convalidated "
    8588             :                                   "FROM pg_catalog.pg_constraint "
    8589             :                                   "WHERE conrelid = '%u'::pg_catalog.oid "
    8590             :                                   "   AND contype = 'c' "
    8591             :                                   "ORDER BY conname",
    8592             :                                   tbinfo->dobj.catId.oid);
    8593             :             }
    8594             :             else
    8595             :             {
    8596           0 :                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
    8597             :                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8598             :                                   "true AS conislocal, true AS convalidated "
    8599             :                                   "FROM pg_catalog.pg_constraint "
    8600             :                                   "WHERE conrelid = '%u'::pg_catalog.oid "
    8601             :                                   "   AND contype = 'c' "
    8602             :                                   "ORDER BY conname",
    8603             :                                   tbinfo->dobj.catId.oid);
    8604             :             }
    8605             : 
    8606         370 :             res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    8607             : 
    8608         370 :             numConstrs = PQntuples(res);
    8609         370 :             if (numConstrs != tbinfo->ncheck)
    8610             :             {
    8611           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    8612             :                                       "expected %d check constraints on table \"%s\" but found %d",
    8613             :                                       tbinfo->ncheck),
    8614             :                              tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
    8615           0 :                 pg_log_error("(The system catalogs might be corrupted.)");
    8616           0 :                 exit_nicely(1);
    8617             :             }
    8618             : 
    8619         370 :             constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    8620         370 :             tbinfo->checkexprs = constrs;
    8621             : 
    8622         904 :             for (j = 0; j < numConstrs; j++)
    8623             :             {
    8624         534 :                 bool        validated = PQgetvalue(res, j, 5)[0] == 't';
    8625             : 
    8626         534 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    8627         534 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
    8628         534 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
    8629         534 :                 AssignDumpId(&constrs[j].dobj);
    8630         534 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
    8631         534 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    8632         534 :                 constrs[j].contable = tbinfo;
    8633         534 :                 constrs[j].condomain = NULL;
    8634         534 :                 constrs[j].contype = 'c';
    8635         534 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
    8636         534 :                 constrs[j].confrelid = InvalidOid;
    8637         534 :                 constrs[j].conindex = 0;
    8638         534 :                 constrs[j].condeferrable = false;
    8639         534 :                 constrs[j].condeferred = false;
    8640         534 :                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
    8641             : 
    8642             :                 /*
    8643             :                  * An unvalidated constraint needs to be dumped separately, so
    8644             :                  * that potentially-violating existing data is loaded before
    8645             :                  * the constraint.
    8646             :                  */
    8647         534 :                 constrs[j].separate = !validated;
    8648             : 
    8649         534 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    8650             : 
    8651             :                 /*
    8652             :                  * Mark the constraint as needing to appear before the table
    8653             :                  * --- this is so that any other dependencies of the
    8654             :                  * constraint will be emitted before we try to create the
    8655             :                  * table.  If the constraint is to be dumped separately, it
    8656             :                  * will be dumped after data is loaded anyway, so don't do it.
    8657             :                  * (There's an automatic dependency in the opposite direction
    8658             :                  * anyway, so don't need to add one manually here.)
    8659             :                  */
    8660         534 :                 if (!constrs[j].separate)
    8661         492 :                     addObjectDependency(&tbinfo->dobj,
    8662         492 :                                         constrs[j].dobj.dumpId);
    8663             : 
    8664             :                 /*
    8665             :                  * If the constraint is inherited, this will be detected later
    8666             :                  * (in pre-8.4 databases).  We also detect later if the
    8667             :                  * constraint must be split out from the table definition.
    8668             :                  */
    8669             :             }
    8670         370 :             PQclear(res);
    8671             :         }
    8672             :     }
    8673             : 
    8674         156 :     destroyPQExpBuffer(q);
    8675         156 : }
    8676             : 
    8677             : /*
    8678             :  * Test whether a column should be printed as part of table's CREATE TABLE.
    8679             :  * Column number is zero-based.
    8680             :  *
    8681             :  * Normally this is always true, but it's false for dropped columns, as well
    8682             :  * as those that were inherited without any local definition.  (If we print
    8683             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
    8684             :  * For partitions, it's always true, because we want the partitions to be
    8685             :  * created independently and ATTACH PARTITION used afterwards.
    8686             :  *
    8687             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
    8688             :  * attisdropped state later, so as to keep control of the physical column
    8689             :  * order.
    8690             :  *
    8691             :  * This function exists because there are scattered nonobvious places that
    8692             :  * must be kept in sync with this decision.
    8693             :  */
    8694             : bool
    8695       36514 : shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
    8696             : {
    8697       36514 :     if (dopt->binary_upgrade)
    8698       10300 :         return true;
    8699       26214 :     if (tbinfo->attisdropped[colno])
    8700         304 :         return false;
    8701       25910 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
    8702             : }
    8703             : 
    8704             : 
    8705             : /*
    8706             :  * getTSParsers:
    8707             :  *    read all text search parsers in the system catalogs and return them
    8708             :  *    in the TSParserInfo* structure
    8709             :  *
    8710             :  *  numTSParsers is set to the number of parsers read in
    8711             :  */
    8712             : TSParserInfo *
    8713         156 : getTSParsers(Archive *fout, int *numTSParsers)
    8714             : {
    8715             :     PGresult   *res;
    8716             :     int         ntups;
    8717             :     int         i;
    8718             :     PQExpBuffer query;
    8719             :     TSParserInfo *prsinfo;
    8720             :     int         i_tableoid;
    8721             :     int         i_oid;
    8722             :     int         i_prsname;
    8723             :     int         i_prsnamespace;
    8724             :     int         i_prsstart;
    8725             :     int         i_prstoken;
    8726             :     int         i_prsend;
    8727             :     int         i_prsheadline;
    8728             :     int         i_prslextype;
    8729             : 
    8730             :     /* Before 8.3, there is no built-in text search support */
    8731         156 :     if (fout->remoteVersion < 80300)
    8732             :     {
    8733           0 :         *numTSParsers = 0;
    8734           0 :         return NULL;
    8735             :     }
    8736             : 
    8737         156 :     query = createPQExpBuffer();
    8738             : 
    8739             :     /*
    8740             :      * find all text search objects, including builtin ones; we filter out
    8741             :      * system-defined objects at dump-out time.
    8742             :      */
    8743             : 
    8744         156 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
    8745             :                          "prsstart::oid, prstoken::oid, "
    8746             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
    8747             :                          "FROM pg_ts_parser");
    8748             : 
    8749         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8750             : 
    8751         156 :     ntups = PQntuples(res);
    8752         156 :     *numTSParsers = ntups;
    8753             : 
    8754         156 :     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
    8755             : 
    8756         156 :     i_tableoid = PQfnumber(res, "tableoid");
    8757         156 :     i_oid = PQfnumber(res, "oid");
    8758         156 :     i_prsname = PQfnumber(res, "prsname");
    8759         156 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
    8760         156 :     i_prsstart = PQfnumber(res, "prsstart");
    8761         156 :     i_prstoken = PQfnumber(res, "prstoken");
    8762         156 :     i_prsend = PQfnumber(res, "prsend");
    8763         156 :     i_prsheadline = PQfnumber(res, "prsheadline");
    8764         156 :     i_prslextype = PQfnumber(res, "prslextype");
    8765             : 
    8766         370 :     for (i = 0; i < ntups; i++)
    8767             :     {
    8768         214 :         prsinfo[i].dobj.objType = DO_TSPARSER;
    8769         214 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8770         214 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8771         214 :         AssignDumpId(&prsinfo[i].dobj);
    8772         214 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
    8773         428 :         prsinfo[i].dobj.namespace =
    8774         214 :             findNamespace(fout,
    8775         214 :                           atooid(PQgetvalue(res, i, i_prsnamespace)));
    8776         214 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
    8777         214 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
    8778         214 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
    8779         214 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
    8780         214 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
    8781             : 
    8782             :         /* Decide whether we want to dump it */
    8783         214 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
    8784             : 
    8785             :         /* Text Search Parsers do not currently have ACLs. */
    8786         214 :         prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    8787             :     }
    8788             : 
    8789         156 :     PQclear(res);
    8790             : 
    8791         156 :     destroyPQExpBuffer(query);
    8792             : 
    8793         156 :     return prsinfo;
    8794             : }
    8795             : 
    8796             : /*
    8797             :  * getTSDictionaries:
    8798             :  *    read all text search dictionaries in the system catalogs and return them
    8799             :  *    in the TSDictInfo* structure
    8800             :  *
    8801             :  *  numTSDicts is set to the number of dictionaries read in
    8802             :  */
    8803             : TSDictInfo *
    8804         156 : getTSDictionaries(Archive *fout, int *numTSDicts)
    8805             : {
    8806             :     PGresult   *res;
    8807             :     int         ntups;
    8808             :     int         i;
    8809             :     PQExpBuffer query;
    8810             :     TSDictInfo *dictinfo;
    8811             :     int         i_tableoid;
    8812             :     int         i_oid;
    8813             :     int         i_dictname;
    8814             :     int         i_dictnamespace;
    8815             :     int         i_rolname;
    8816             :     int         i_dicttemplate;
    8817             :     int         i_dictinitoption;
    8818             : 
    8819             :     /* Before 8.3, there is no built-in text search support */
    8820         156 :     if (fout->remoteVersion < 80300)
    8821             :     {
    8822           0 :         *numTSDicts = 0;
    8823           0 :         return NULL;
    8824             :     }
    8825             : 
    8826         156 :     query = createPQExpBuffer();
    8827             : 
    8828         156 :     appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
    8829             :                       "dictnamespace, (%s dictowner) AS rolname, "
    8830             :                       "dicttemplate, dictinitoption "
    8831             :                       "FROM pg_ts_dict",
    8832             :                       username_subquery);
    8833             : 
    8834         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8835             : 
    8836         156 :     ntups = PQntuples(res);
    8837         156 :     *numTSDicts = ntups;
    8838             : 
    8839         156 :     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
    8840             : 
    8841         156 :     i_tableoid = PQfnumber(res, "tableoid");
    8842         156 :     i_oid = PQfnumber(res, "oid");
    8843         156 :     i_dictname = PQfnumber(res, "dictname");
    8844         156 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
    8845         156 :     i_rolname = PQfnumber(res, "rolname");
    8846         156 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
    8847         156 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
    8848             : 
    8849        3856 :     for (i = 0; i < ntups; i++)
    8850             :     {
    8851        3700 :         dictinfo[i].dobj.objType = DO_TSDICT;
    8852        3700 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8853        3700 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8854        3700 :         AssignDumpId(&dictinfo[i].dobj);
    8855        3700 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
    8856        7400 :         dictinfo[i].dobj.namespace =
    8857        3700 :             findNamespace(fout,
    8858        3700 :                           atooid(PQgetvalue(res, i, i_dictnamespace)));
    8859        3700 :         dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    8860        3700 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
    8861        3700 :         if (PQgetisnull(res, i, i_dictinitoption))
    8862         214 :             dictinfo[i].dictinitoption = NULL;
    8863             :         else
    8864        3486 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
    8865             : 
    8866             :         /* Decide whether we want to dump it */
    8867        3700 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
    8868             : 
    8869             :         /* Text Search Dictionaries do not currently have ACLs. */
    8870        3700 :         dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    8871             :     }
    8872             : 
    8873         156 :     PQclear(res);
    8874             : 
    8875         156 :     destroyPQExpBuffer(query);
    8876             : 
    8877         156 :     return dictinfo;
    8878             : }
    8879             : 
    8880             : /*
    8881             :  * getTSTemplates:
    8882             :  *    read all text search templates in the system catalogs and return them
    8883             :  *    in the TSTemplateInfo* structure
    8884             :  *
    8885             :  *  numTSTemplates is set to the number of templates read in
    8886             :  */
    8887             : TSTemplateInfo *
    8888         156 : getTSTemplates(Archive *fout, int *numTSTemplates)
    8889             : {
    8890             :     PGresult   *res;
    8891             :     int         ntups;
    8892             :     int         i;
    8893             :     PQExpBuffer query;
    8894             :     TSTemplateInfo *tmplinfo;
    8895             :     int         i_tableoid;
    8896             :     int         i_oid;
    8897             :     int         i_tmplname;
    8898             :     int         i_tmplnamespace;
    8899             :     int         i_tmplinit;
    8900             :     int         i_tmpllexize;
    8901             : 
    8902             :     /* Before 8.3, there is no built-in text search support */
    8903         156 :     if (fout->remoteVersion < 80300)
    8904             :     {
    8905           0 :         *numTSTemplates = 0;
    8906           0 :         return NULL;
    8907             :     }
    8908             : 
    8909         156 :     query = createPQExpBuffer();
    8910             : 
    8911         156 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
    8912             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
    8913             :                          "FROM pg_ts_template");
    8914             : 
    8915         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8916             : 
    8917         156 :     ntups = PQntuples(res);
    8918         156 :     *numTSTemplates = ntups;
    8919             : 
    8920         156 :     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
    8921             : 
    8922         156 :     i_tableoid = PQfnumber(res, "tableoid");
    8923         156 :     i_oid = PQfnumber(res, "oid");
    8924         156 :     i_tmplname = PQfnumber(res, "tmplname");
    8925         156 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
    8926         156 :     i_tmplinit = PQfnumber(res, "tmplinit");
    8927         156 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
    8928             : 
    8929         994 :     for (i = 0; i < ntups; i++)
    8930             :     {
    8931         838 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
    8932         838 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8933         838 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8934         838 :         AssignDumpId(&tmplinfo[i].dobj);
    8935         838 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
    8936        1676 :         tmplinfo[i].dobj.namespace =
    8937         838 :             findNamespace(fout,
    8938         838 :                           atooid(PQgetvalue(res, i, i_tmplnamespace)));
    8939         838 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
    8940         838 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
    8941             : 
    8942             :         /* Decide whether we want to dump it */
    8943         838 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
    8944             : 
    8945             :         /* Text Search Templates do not currently have ACLs. */
    8946         838 :         tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    8947             :     }
    8948             : 
    8949         156 :     PQclear(res);
    8950             : 
    8951         156 :     destroyPQExpBuffer(query);
    8952             : 
    8953         156 :     return tmplinfo;
    8954             : }
    8955             : 
    8956             : /*
    8957             :  * getTSConfigurations:
    8958             :  *    read all text search configurations in the system catalogs and return
    8959             :  *    them in the TSConfigInfo* structure
    8960             :  *
    8961             :  *  numTSConfigs is set to the number of configurations read in
    8962             :  */
    8963             : TSConfigInfo *
    8964         156 : getTSConfigurations(Archive *fout, int *numTSConfigs)
    8965             : {
    8966             :     PGresult   *res;
    8967             :     int         ntups;
    8968             :     int         i;
    8969             :     PQExpBuffer query;
    8970             :     TSConfigInfo *cfginfo;
    8971             :     int         i_tableoid;
    8972             :     int         i_oid;
    8973             :     int         i_cfgname;
    8974             :     int         i_cfgnamespace;
    8975             :     int         i_rolname;
    8976             :     int         i_cfgparser;
    8977             : 
    8978             :     /* Before 8.3, there is no built-in text search support */
    8979         156 :     if (fout->remoteVersion < 80300)
    8980             :     {
    8981           0 :         *numTSConfigs = 0;
    8982           0 :         return NULL;
    8983             :     }
    8984             : 
    8985         156 :     query = createPQExpBuffer();
    8986             : 
    8987         156 :     appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
    8988             :                       "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
    8989             :                       "FROM pg_ts_config",
    8990             :                       username_subquery);
    8991             : 
    8992         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8993             : 
    8994         156 :     ntups = PQntuples(res);
    8995         156 :     *numTSConfigs = ntups;
    8996             : 
    8997         156 :     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
    8998             : 
    8999         156 :     i_tableoid = PQfnumber(res, "tableoid");
    9000         156 :     i_oid = PQfnumber(res, "oid");
    9001         156 :     i_cfgname = PQfnumber(res, "cfgname");
    9002         156 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
    9003         156 :     i_rolname = PQfnumber(res, "rolname");
    9004         156 :     i_cfgparser = PQfnumber(res, "cfgparser");
    9005             : 
    9006        3826 :     for (i = 0; i < ntups; i++)
    9007             :     {
    9008        3670 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
    9009        3670 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9010        3670 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9011        3670 :         AssignDumpId(&cfginfo[i].dobj);
    9012        3670 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
    9013        7340 :         cfginfo[i].dobj.namespace =
    9014        3670 :             findNamespace(fout,
    9015        3670 :                           atooid(PQgetvalue(res, i, i_cfgnamespace)));
    9016        3670 :         cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    9017        3670 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
    9018             : 
    9019             :         /* Decide whether we want to dump it */
    9020        3670 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
    9021             : 
    9022             :         /* Text Search Configurations do not currently have ACLs. */
    9023        3670 :         cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    9024             :     }
    9025             : 
    9026         156 :     PQclear(res);
    9027             : 
    9028         156 :     destroyPQExpBuffer(query);
    9029             : 
    9030         156 :     return cfginfo;
    9031             : }
    9032             : 
    9033             : /*
    9034             :  * getForeignDataWrappers:
    9035             :  *    read all foreign-data wrappers in the system catalogs and return
    9036             :  *    them in the FdwInfo* structure
    9037             :  *
    9038             :  *  numForeignDataWrappers is set to the number of fdws read in
    9039             :  */
    9040             : FdwInfo *
    9041         156 : getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
    9042             : {
    9043         156 :     DumpOptions *dopt = fout->dopt;
    9044             :     PGresult   *res;
    9045             :     int         ntups;
    9046             :     int         i;
    9047             :     PQExpBuffer query;
    9048             :     FdwInfo    *fdwinfo;
    9049             :     int         i_tableoid;
    9050             :     int         i_oid;
    9051             :     int         i_fdwname;
    9052             :     int         i_rolname;
    9053             :     int         i_fdwhandler;
    9054             :     int         i_fdwvalidator;
    9055             :     int         i_fdwacl;
    9056             :     int         i_rfdwacl;
    9057             :     int         i_initfdwacl;
    9058             :     int         i_initrfdwacl;
    9059             :     int         i_fdwoptions;
    9060             : 
    9061             :     /* Before 8.4, there are no foreign-data wrappers */
    9062         156 :     if (fout->remoteVersion < 80400)
    9063             :     {
    9064           0 :         *numForeignDataWrappers = 0;
    9065           0 :         return NULL;
    9066             :     }
    9067             : 
    9068         156 :     query = createPQExpBuffer();
    9069             : 
    9070         156 :     if (fout->remoteVersion >= 90600)
    9071             :     {
    9072         156 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    9073         156 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    9074         156 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    9075         156 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    9076             : 
    9077         156 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    9078             :                         initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
    9079         156 :                         dopt->binary_upgrade);
    9080             : 
    9081         156 :         appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
    9082             :                           "(%s f.fdwowner) AS rolname, "
    9083             :                           "f.fdwhandler::pg_catalog.regproc, "
    9084             :                           "f.fdwvalidator::pg_catalog.regproc, "
    9085             :                           "%s AS fdwacl, "
    9086             :                           "%s AS rfdwacl, "
    9087             :                           "%s AS initfdwacl, "
    9088             :                           "%s AS initrfdwacl, "
    9089             :                           "array_to_string(ARRAY("
    9090             :                           "SELECT quote_ident(option_name) || ' ' || "
    9091             :                           "quote_literal(option_value) "
    9092             :                           "FROM pg_options_to_table(f.fdwoptions) "
    9093             :                           "ORDER BY option_name"
    9094             :                           "), E',\n    ') AS fdwoptions "
    9095             :                           "FROM pg_foreign_data_wrapper f "
    9096             :                           "LEFT JOIN pg_init_privs pip ON "
    9097             :                           "(f.oid = pip.objoid "
    9098             :                           "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
    9099             :                           "AND pip.objsubid = 0) ",
    9100             :                           username_subquery,
    9101             :                           acl_subquery->data,
    9102             :                           racl_subquery->data,
    9103             :                           initacl_subquery->data,
    9104             :                           initracl_subquery->data);
    9105             : 
    9106         156 :         destroyPQExpBuffer(acl_subquery);
    9107         156 :         destroyPQExpBuffer(racl_subquery);
    9108         156 :         destroyPQExpBuffer(initacl_subquery);
    9109         156 :         destroyPQExpBuffer(initracl_subquery);
    9110             :     }
    9111           0 :     else if (fout->remoteVersion >= 90100)
    9112             :     {
    9113           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
    9114             :                           "(%s fdwowner) AS rolname, "
    9115             :                           "fdwhandler::pg_catalog.regproc, "
    9116             :                           "fdwvalidator::pg_catalog.regproc, fdwacl, "
    9117             :                           "NULL as rfdwacl, "
    9118             :                           "NULL as initfdwacl, NULL AS initrfdwacl, "
    9119             :                           "array_to_string(ARRAY("
    9120             :                           "SELECT quote_ident(option_name) || ' ' || "
    9121             :                           "quote_literal(option_value) "
    9122             :                           "FROM pg_options_to_table(fdwoptions) "
    9123             :                           "ORDER BY option_name"
    9124             :                           "), E',\n    ') AS fdwoptions "
    9125             :                           "FROM pg_foreign_data_wrapper",
    9126             :                           username_subquery);
    9127             :     }
    9128             :     else
    9129             :     {
    9130           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
    9131             :                           "(%s fdwowner) AS rolname, "
    9132             :                           "'-' AS fdwhandler, "
    9133             :                           "fdwvalidator::pg_catalog.regproc, fdwacl, "
    9134             :                           "NULL as rfdwacl, "
    9135             :                           "NULL as initfdwacl, NULL AS initrfdwacl, "
    9136             :                           "array_to_string(ARRAY("
    9137             :                           "SELECT quote_ident(option_name) || ' ' || "
    9138             :                           "quote_literal(option_value) "
    9139             :                           "FROM pg_options_to_table(fdwoptions) "
    9140             :                           "ORDER BY option_name"
    9141             :                           "), E',\n    ') AS fdwoptions "
    9142             :                           "FROM pg_foreign_data_wrapper",
    9143             :                           username_subquery);
    9144             :     }
    9145             : 
    9146         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9147             : 
    9148         156 :     ntups = PQntuples(res);
    9149         156 :     *numForeignDataWrappers = ntups;
    9150             : 
    9151         156 :     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
    9152             : 
    9153         156 :     i_tableoid = PQfnumber(res, "tableoid");
    9154         156 :     i_oid = PQfnumber(res, "oid");
    9155         156 :     i_fdwname = PQfnumber(res, "fdwname");
    9156         156 :     i_rolname = PQfnumber(res, "rolname");
    9157         156 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
    9158         156 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
    9159         156 :     i_fdwacl = PQfnumber(res, "fdwacl");
    9160         156 :     i_rfdwacl = PQfnumber(res, "rfdwacl");
    9161         156 :     i_initfdwacl = PQfnumber(res, "initfdwacl");
    9162         156 :     i_initrfdwacl = PQfnumber(res, "initrfdwacl");
    9163         156 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
    9164             : 
    9165         220 :     for (i = 0; i < ntups; i++)
    9166             :     {
    9167          64 :         fdwinfo[i].dobj.objType = DO_FDW;
    9168          64 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9169          64 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9170          64 :         AssignDumpId(&fdwinfo[i].dobj);
    9171          64 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
    9172          64 :         fdwinfo[i].dobj.namespace = NULL;
    9173          64 :         fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    9174          64 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
    9175          64 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
    9176          64 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
    9177          64 :         fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
    9178          64 :         fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
    9179          64 :         fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
    9180          64 :         fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
    9181             : 
    9182             :         /* Decide whether we want to dump it */
    9183          64 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
    9184             : 
    9185             :         /* Do not try to dump ACL if no ACL exists. */
    9186          70 :         if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
    9187          12 :             PQgetisnull(res, i, i_initfdwacl) &&
    9188           6 :             PQgetisnull(res, i, i_initrfdwacl))
    9189           6 :             fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    9190             :     }
    9191             : 
    9192         156 :     PQclear(res);
    9193             : 
    9194         156 :     destroyPQExpBuffer(query);
    9195             : 
    9196         156 :     return fdwinfo;
    9197             : }
    9198             : 
    9199             : /*
    9200             :  * getForeignServers:
    9201             :  *    read all foreign servers in the system catalogs and return
    9202             :  *    them in the ForeignServerInfo * structure
    9203             :  *
    9204             :  *  numForeignServers is set to the number of servers read in
    9205             :  */
    9206             : ForeignServerInfo *
    9207         156 : getForeignServers(Archive *fout, int *numForeignServers)
    9208             : {
    9209         156 :     DumpOptions *dopt = fout->dopt;
    9210             :     PGresult   *res;
    9211             :     int         ntups;
    9212             :     int         i;
    9213             :     PQExpBuffer query;
    9214             :     ForeignServerInfo *srvinfo;
    9215             :     int         i_tableoid;
    9216             :     int         i_oid;
    9217             :     int         i_srvname;
    9218             :     int         i_rolname;
    9219             :     int         i_srvfdw;
    9220             :     int         i_srvtype;
    9221             :     int         i_srvversion;
    9222             :     int         i_srvacl;
    9223             :     int         i_rsrvacl;
    9224             :     int         i_initsrvacl;
    9225             :     int         i_initrsrvacl;
    9226             :     int         i_srvoptions;
    9227             : 
    9228             :     /* Before 8.4, there are no foreign servers */
    9229         156 :     if (fout->remoteVersion < 80400)
    9230             :     {
    9231           0 :         *numForeignServers = 0;
    9232           0 :         return NULL;
    9233             :     }
    9234             : 
    9235         156 :     query = createPQExpBuffer();
    9236             : 
    9237         156 :     if (fout->remoteVersion >= 90600)
    9238             :     {
    9239         156 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    9240         156 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    9241         156 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    9242         156 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    9243             : 
    9244         156 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    9245             :                         initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
    9246         156 :                         dopt->binary_upgrade);
    9247             : 
    9248         156 :         appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
    9249             :                           "(%s f.srvowner) AS rolname, "
    9250             :                           "f.srvfdw, f.srvtype, f.srvversion, "
    9251             :                           "%s AS srvacl, "
    9252             :                           "%s AS rsrvacl, "
    9253             :                           "%s AS initsrvacl, "
    9254             :                           "%s AS initrsrvacl, "
    9255             :                           "array_to_string(ARRAY("
    9256             :                           "SELECT quote_ident(option_name) || ' ' || "
    9257             :                           "quote_literal(option_value) "
    9258             :                           "FROM pg_options_to_table(f.srvoptions) "
    9259             :                           "ORDER BY option_name"
    9260             :                           "), E',\n    ') AS srvoptions "
    9261             :                           "FROM pg_foreign_server f "
    9262             :                           "LEFT JOIN pg_init_privs pip "
    9263             :                           "ON (f.oid = pip.objoid "
    9264             :                           "AND pip.classoid = 'pg_foreign_server'::regclass "
    9265             :                           "AND pip.objsubid = 0) ",
    9266             :                           username_subquery,
    9267             :                           acl_subquery->data,
    9268             :                           racl_subquery->data,
    9269             :                           initacl_subquery->data,
    9270             :                           initracl_subquery->data);
    9271             : 
    9272         156 :         destroyPQExpBuffer(acl_subquery);
    9273         156 :         destroyPQExpBuffer(racl_subquery);
    9274         156 :         destroyPQExpBuffer(initacl_subquery);
    9275         156 :         destroyPQExpBuffer(initracl_subquery);
    9276             :     }
    9277             :     else
    9278             :     {
    9279           0 :         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
    9280             :                           "(%s srvowner) AS rolname, "
    9281             :                           "srvfdw, srvtype, srvversion, srvacl, "
    9282             :                           "NULL AS rsrvacl, "
    9283             :                           "NULL AS initsrvacl, NULL AS initrsrvacl, "
    9284             :                           "array_to_string(ARRAY("
    9285             :                           "SELECT quote_ident(option_name) || ' ' || "
    9286             :                           "quote_literal(option_value) "
    9287             :                           "FROM pg_options_to_table(srvoptions) "
    9288             :                           "ORDER BY option_name"
    9289             :                           "), E',\n    ') AS srvoptions "
    9290             :                           "FROM pg_foreign_server",
    9291             :                           username_subquery);
    9292             :     }
    9293             : 
    9294         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9295             : 
    9296         156 :     ntups = PQntuples(res);
    9297         156 :     *numForeignServers = ntups;
    9298             : 
    9299         156 :     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
    9300             : 
    9301         156 :     i_tableoid = PQfnumber(res, "tableoid");
    9302         156 :     i_oid = PQfnumber(res, "oid");
    9303         156 :     i_srvname = PQfnumber(res, "srvname");
    9304         156 :     i_rolname = PQfnumber(res, "rolname");
    9305         156 :     i_srvfdw = PQfnumber(res, "srvfdw");
    9306         156 :     i_srvtype = PQfnumber(res, "srvtype");
    9307         156 :     i_srvversion = PQfnumber(res, "srvversion");
    9308         156 :     i_srvacl = PQfnumber(res, "srvacl");
    9309         156 :     i_rsrvacl = PQfnumber(res, "rsrvacl");
    9310         156 :     i_initsrvacl = PQfnumber(res, "initsrvacl");
    9311         156 :     i_initrsrvacl = PQfnumber(res, "initrsrvacl");
    9312         156 :     i_srvoptions = PQfnumber(res, "srvoptions");
    9313             : 
    9314         220 :     for (i = 0; i < ntups; i++)
    9315             :     {
    9316          64 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
    9317          64 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9318          64 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9319          64 :         AssignDumpId(&srvinfo[i].dobj);
    9320          64 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
    9321          64 :         srvinfo[i].dobj.namespace = NULL;
    9322          64 :         srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
    9323          64 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
    9324          64 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
    9325          64 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
    9326          64 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
    9327          64 :         srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
    9328          64 :         srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
    9329          64 :         srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
    9330          64 :         srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
    9331             : 
    9332             :         /* Decide whether we want to dump it */
    9333          64 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
    9334             : 
    9335             :         /* Do not try to dump ACL if no ACL exists. */
    9336          70 :         if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
    9337          12 :             PQgetisnull(res, i, i_initsrvacl) &&
    9338           6 :             PQgetisnull(res, i, i_initrsrvacl))
    9339           6 :             srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
    9340             :     }
    9341             : 
    9342         156 :     PQclear(res);
    9343             : 
    9344         156 :     destroyPQExpBuffer(query);
    9345             : 
    9346         156 :     return srvinfo;
    9347             : }
    9348             : 
    9349             : /*
    9350             :  * getDefaultACLs:
    9351             :  *    read all default ACL information in the system catalogs and return
    9352             :  *    them in the DefaultACLInfo structure
    9353             :  *
    9354             :  *  numDefaultACLs is set to the number of ACLs read in
    9355             :  */
    9356             : DefaultACLInfo *
    9357         156 : getDefaultACLs(Archive *fout, int *numDefaultACLs)
    9358             : {
    9359         156 :     DumpOptions *dopt = fout->dopt;
    9360             :     DefaultACLInfo *daclinfo;
    9361             :     PQExpBuffer query;
    9362             :     PGresult   *res;
    9363             :     int         i_oid;
    9364             :     int         i_tableoid;
    9365             :     int         i_defaclrole;
    9366             :     int         i_defaclnamespace;
    9367             :     int         i_defaclobjtype;
    9368             :     int         i_defaclacl;
    9369             :     int         i_rdefaclacl;
    9370             :     int         i_initdefaclacl;
    9371             :     int         i_initrdefaclacl;
    9372             :     int         i,
    9373             :                 ntups;
    9374             : 
    9375         156 :     if (fout->remoteVersion < 90000)
    9376             :     {
    9377           0 :         *numDefaultACLs = 0;
    9378           0 :         return NULL;
    9379             :     }
    9380             : 
    9381         156 :     query = createPQExpBuffer();
    9382             : 
    9383         156 :     if (fout->remoteVersion >= 90600)
    9384             :     {
    9385         156 :         PQExpBuffer acl_subquery = createPQExpBuffer();
    9386         156 :         PQExpBuffer racl_subquery = createPQExpBuffer();
    9387         156 :         PQExpBuffer initacl_subquery = createPQExpBuffer();
    9388         156 :         PQExpBuffer initracl_subquery = createPQExpBuffer();
    9389             : 
    9390         156 :         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
    9391             :                         initracl_subquery, "defaclacl", "defaclrole",
    9392             :                         "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
    9393         156 :                         dopt->binary_upgrade);
    9394             : 
    9395         156 :         appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
    9396             :                           "(%s d.defaclrole) AS defaclrole, "
    9397             :                           "d.defaclnamespace, "
    9398             :                           "d.defaclobjtype, "
    9399             :                           "%s AS defaclacl, "
    9400             :                           "%s AS rdefaclacl, "
    9401             :                           "%s AS initdefaclacl, "
    9402             :                           "%s AS initrdefaclacl "
    9403             :                           "FROM pg_default_acl d "
    9404             :                           "LEFT JOIN pg_init_privs pip ON "
    9405             :                           "(d.oid = pip.objoid "
    9406             :                           "AND pip.classoid = 'pg_default_acl'::regclass "
    9407             :                           "AND pip.objsubid = 0) ",
    9408             :                           username_subquery,
    9409             :                           acl_subquery->data,
    9410             :                           racl_subquery->data,
    9411             :                           initacl_subquery->data,
    9412             :                           initracl_subquery->data);
    9413             :     }
    9414             :     else
    9415             :     {
    9416           0 :         appendPQExpBuffer(query, "SELECT oid, tableoid, "
    9417             :                           "(%s defaclrole) AS defaclrole, "
    9418             :                           "defaclnamespace, "
    9419             :                           "defaclobjtype, "
    9420             :                           "defaclacl, "
    9421             :                           "NULL AS rdefaclacl, "
    9422             :                           "NULL AS initdefaclacl, "
    9423             :                           "NULL AS initrdefaclacl "
    9424             :                           "FROM pg_default_acl",
    9425             :                           username_subquery);
    9426             :     }
    9427             : 
    9428         156 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9429             : 
    9430         156 :     ntups = PQntuples(res);
    9431         156 :     *numDefaultACLs = ntups;
    9432             : 
    9433         156 :     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
    9434             : 
    9435         156 :     i_oid = PQfnumber(res, "oid");
    9436         156 :     i_tableoid = PQfnumber(res, "tableoid");
    9437         156 :     i_defaclrole = PQfnumber(res, "defaclrole");
    9438         156 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
    9439         156 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
    9440         156 :     i_defaclacl = PQfnumber(res, "defaclacl");
    9441         156 :     i_rdefaclacl = PQfnumber(res, "rdefaclacl");
    9442         156 :     i_initdefaclacl = PQfnumber(res, "initdefaclacl");
    9443         156 :     i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
    9444             : 
    9445         330 :     for (i = 0; i < ntups; i++)
    9446             :     {
    9447         174 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
    9448             : 
    9449         174 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
    9450         174 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9451         174 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9452         174 :         AssignDumpId(&daclinfo[i].dobj);
    9453             :         /* cheesy ... is it worth coming up with a better object name? */
    9454         174 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
    9455             : 
    9456         174 :         if (nspid != InvalidOid)
    9457          58 :             daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
    9458             :         else
    9459         116 :             daclinfo[i].dobj.namespace = NULL;
    9460             : 
    9461         174 :         daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
    9462         174 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
    9463         174 :         daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
    9464         174 :         daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
    9465         174 :         daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
    9466         174 :         daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
    9467             : 
    9468             :         /* Decide whether we want to dump it */
    9469         174 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
    9470             :     }
    9471             : 
    9472         156 :     PQclear(res);
    9473             : 
    9474         156 :     destroyPQExpBuffer(query);
    9475             : 
    9476         156 :     return daclinfo;
    9477             : }
    9478             : 
    9479             : /*
    9480             :  * dumpComment --
    9481             :  *
    9482             :  * This routine is used to dump any comments associated with the
    9483             :  * object handed to this routine. The routine takes the object type
    9484             :  * and object name (ready to print, except for schema decoration), plus
    9485             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
    9486             :  * plus catalog ID and subid which are the lookup key for pg_description,
    9487             :  * plus the dump ID for the object (for setting a dependency).
    9488             :  * If a matching pg_description entry is found, it is dumped.
    9489             :  *
    9490             :  * Note: in some cases, such as comments for triggers and rules, the "type"
    9491             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
    9492             :  * but it doesn't seem worth complicating the API for all callers to make
    9493             :  * it cleaner.
    9494             :  *
    9495             :  * Note: although this routine takes a dumpId for dependency purposes,
    9496             :  * that purpose is just to mark the dependency in the emitted dump file
    9497             :  * for possible future use by pg_restore.  We do NOT use it for determining
    9498             :  * ordering of the comment in the dump file, because this routine is called
    9499             :  * after dependency sorting occurs.  This routine should be called just after
    9500             :  * calling ArchiveEntry() for the specified object.
    9501             :  */
    9502             : static void
    9503        8192 : dumpComment(Archive *fout, const char *type, const char *name,
    9504             :             const char *namespace, const char *owner,
    9505             :             CatalogId catalogId, int subid, DumpId dumpId)
    9506             : {
    9507        8192 :     DumpOptions *dopt = fout->dopt;
    9508             :     CommentItem *comments;
    9509             :     int         ncomments;
    9510             : 
    9511             :     /* do nothing, if --no-comments is supplied */
    9512        8192 :     if (dopt->no_comments)
    9513          12 :         return;
    9514             : 
    9515             :     /* Comments are schema not data ... except blob comments are data */
    9516        8192 :     if (strcmp(type, "LARGE OBJECT") != 0)
    9517             :     {
    9518        8130 :         if (dopt->dataOnly)
    9519          12 :             return;
    9520             :     }
    9521             :     else
    9522             :     {
    9523             :         /* We do dump blob comments in binary-upgrade mode */
    9524          62 :         if (dopt->schemaOnly && !dopt->binary_upgrade)
    9525           0 :             return;
    9526             :     }
    9527             : 
    9528             :     /* Search for comments associated with catalogId, using table */
    9529        8180 :     ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
    9530             :                              &comments);
    9531             : 
    9532             :     /* Is there one matching the subid? */
    9533       16360 :     while (ncomments > 0)
    9534             :     {
    9535         656 :         if (comments->objsubid == subid)
    9536         656 :             break;
    9537           0 :         comments++;
    9538           0 :         ncomments--;
    9539             :     }
    9540             : 
    9541             :     /* If a comment exists, build COMMENT ON statement */
    9542        8180 :     if (ncomments > 0)
    9543             :     {
    9544         656 :         PQExpBuffer query = createPQExpBuffer();
    9545         656 :         PQExpBuffer tag = createPQExpBuffer();
    9546             : 
    9547         656 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
    9548         656 :         if (namespace && *namespace)
    9549         486 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
    9550         656 :         appendPQExpBuffer(query, "%s IS ", name);
    9551         656 :         appendStringLiteralAH(query, comments->descr, fout);
    9552         656 :         appendPQExpBufferStr(query, ";\n");
    9553             : 
    9554         656 :         appendPQExpBuffer(tag, "%s %s", type, name);
    9555             : 
    9556             :         /*
    9557             :          * We mark comments as SECTION_NONE because they really belong in the
    9558             :          * same section as their parent, whether that is pre-data or
    9559             :          * post-data.
    9560             :          */
    9561         656 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    9562         656 :                      ARCHIVE_OPTS(.tag = tag->data,
    9563             :                                   .namespace = namespace,
    9564             :                                   .owner = owner,
    9565             :                                   .description = "COMMENT",
    9566             :                                   .section = SECTION_NONE,
    9567             :                                   .createStmt = query->data,
    9568             :                                   .deps = &dumpId,
    9569             :                                   .nDeps = 1));
    9570             : 
    9571         656 :         destroyPQExpBuffer(query);
    9572         656 :         destroyPQExpBuffer(tag);
    9573             :     }
    9574             : }
    9575             : 
    9576             : /*
    9577             :  * dumpTableComment --
    9578             :  *
    9579             :  * As above, but dump comments for both the specified table (or view)
    9580             :  * and its columns.
    9581             :  */
    9582             : static void
    9583        4614 : dumpTableComment(Archive *fout, TableInfo *tbinfo,
    9584             :                  const char *reltypename)
    9585             : {
    9586        4614 :     DumpOptions *dopt = fout->dopt;
    9587             :     CommentItem *comments;
    9588             :     int         ncomments;
    9589             :     PQExpBuffer query;
    9590             :     PQExpBuffer tag;
    9591             : 
    9592             :     /* do nothing, if --no-comments is supplied */
    9593        4614 :     if (dopt->no_comments)
    9594        4514 :         return;
    9595             : 
    9596             :     /* Comments are SCHEMA not data */
    9597        4614 :     if (dopt->dataOnly)
    9598           0 :         return;
    9599             : 
    9600             :     /* Search for comments associated with relation, using table */
    9601        4614 :     ncomments = findComments(fout,
    9602             :                              tbinfo->dobj.catId.tableoid,
    9603             :                              tbinfo->dobj.catId.oid,
    9604             :                              &comments);
    9605             : 
    9606             :     /* If comments exist, build COMMENT ON statements */
    9607        4614 :     if (ncomments <= 0)
    9608        4514 :         return;
    9609             : 
    9610         100 :     query = createPQExpBuffer();
    9611         100 :     tag = createPQExpBuffer();
    9612             : 
    9613         388 :     while (ncomments > 0)
    9614             :     {
    9615         188 :         const char *descr = comments->descr;
    9616         188 :         int         objsubid = comments->objsubid;
    9617             : 
    9618         188 :         if (objsubid == 0)
    9619             :         {
    9620          44 :             resetPQExpBuffer(tag);
    9621          44 :             appendPQExpBuffer(tag, "%s %s", reltypename,
    9622          44 :                               fmtId(tbinfo->dobj.name));
    9623             : 
    9624          44 :             resetPQExpBuffer(query);
    9625          44 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
    9626          44 :                               fmtQualifiedDumpable(tbinfo));
    9627          44 :             appendStringLiteralAH(query, descr, fout);
    9628          44 :             appendPQExpBufferStr(query, ";\n");
    9629             : 
    9630          44 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    9631          44 :                          ARCHIVE_OPTS(.tag = tag->data,
    9632             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
    9633             :                                       .owner = tbinfo->rolname,
    9634             :                                       .description = "COMMENT",
    9635             :                                       .section = SECTION_NONE,
    9636             :                                       .createStmt = query->data,
    9637             :                                       .deps = &(tbinfo->dobj.dumpId),
    9638             :                                       .nDeps = 1));
    9639             :         }
    9640         144 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
    9641             :         {
    9642         144 :             resetPQExpBuffer(tag);
    9643         144 :             appendPQExpBuffer(tag, "COLUMN %s.",
    9644         144 :                               fmtId(tbinfo->dobj.name));
    9645         144 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
    9646             : 
    9647         144 :             resetPQExpBuffer(query);
    9648         144 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
    9649         144 :                               fmtQualifiedDumpable(tbinfo));
    9650         144 :             appendPQExpBuffer(query, "%s IS ",
    9651         144 :                               fmtId(tbinfo->attnames[objsubid - 1]));
    9652         144 :             appendStringLiteralAH(query, descr, fout);
    9653         144 :             appendPQExpBufferStr(query, ";\n");
    9654             : 
    9655         144 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    9656         144 :                          ARCHIVE_OPTS(.tag = tag->data,
    9657             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
    9658             :                                       .owner = tbinfo->rolname,
    9659             :                                       .description = "COMMENT",
    9660             :                                       .section = SECTION_NONE,
    9661             :                                       .createStmt = query->data,
    9662             :                                       .deps = &(tbinfo->dobj.dumpId),
    9663             :                                       .nDeps = 1));
    9664             :         }
    9665             : 
    9666         188 :         comments++;
    9667         188 :         ncomments--;
    9668             :     }
    9669             : 
    9670         100 :     destroyPQExpBuffer(query);
    9671         100 :     destroyPQExpBuffer(tag);
    9672             : }
    9673             : 
    9674             : /*
    9675             :  * findComments --
    9676             :  *
    9677             :  * Find the comment(s), if any, associated with the given object.  All the
    9678             :  * objsubid values associated with the given classoid/objoid are found with
    9679             :  * one search.
    9680             :  */
    9681             : static int
    9682       12936 : findComments(Archive *fout, Oid classoid, Oid objoid,
    9683             :              CommentItem **items)
    9684             : {
    9685             :     /* static storage for table of comments */
    9686             :     static CommentItem *comments = NULL;
    9687             :     static int  ncomments = -1;
    9688             : 
    9689       12936 :     CommentItem *middle = NULL;
    9690             :     CommentItem *low;
    9691             :     CommentItem *high;
    9692             :     int         nmatch;
    9693             : 
    9694             :     /* Get comments if we didn't already */
    9695       12936 :     if (ncomments < 0)
    9696          98 :         ncomments = collectComments(fout, &comments);
    9697             : 
    9698             :     /*
    9699             :      * Do binary search to find some item matching the object.
    9700             :      */
    9701       12936 :     low = &comments[0];
    9702       12936 :     high = &comments[ncomments - 1];
    9703      179640 :     while (low <= high)
    9704             :     {
    9705      154568 :         middle = low + (high - low) / 2;
    9706             : 
    9707      154568 :         if (classoid < middle->classoid)
    9708       72764 :             high = middle - 1;
    9709       81804 :         else if (classoid > middle->classoid)
    9710       46080 :             low = middle + 1;
    9711       35724 :         else if (objoid < middle->objoid)
    9712       15948 :             high = middle - 1;
    9713       19776 :         else if (objoid > middle->objoid)
    9714       18976 :             low = middle + 1;
    9715             :         else
    9716         800 :             break;              /* found a match */
    9717             :     }
    9718             : 
    9719       12936 :     if (low > high)              /* no matches */
    9720             :     {
    9721       12136 :         *items = NULL;
    9722       12136 :         return 0;
    9723             :     }
    9724             : 
    9725             :     /*
    9726             :      * Now determine how many items match the object.  The search loop
    9727             :      * invariant still holds: only items between low and high inclusive could
    9728             :      * match.
    9729             :      */
    9730         800 :     nmatch = 1;
    9731        1688 :     while (middle > low)
    9732             :     {
    9733         596 :         if (classoid != middle[-1].classoid ||
    9734         230 :             objoid != middle[-1].objoid)
    9735             :             break;
    9736          88 :         middle--;
    9737          88 :         nmatch++;
    9738             :     }
    9739             : 
    9740         800 :     *items = middle;
    9741             : 
    9742         800 :     middle += nmatch;
    9743        1600 :     while (middle <= high)
    9744             :     {
    9745         478 :         if (classoid != middle->classoid ||
    9746         156 :             objoid != middle->objoid)
    9747             :             break;
    9748           0 :         middle++;
    9749           0 :         nmatch++;
    9750             :     }
    9751             : 
    9752         800 :     return nmatch;
    9753             : }
    9754             : 
    9755             : /*
    9756             :  * collectComments --
    9757             :  *
    9758             :  * Construct a table of all comments available for database objects.
    9759             :  * We used to do per-object queries for the comments, but it's much faster
    9760             :  * to pull them all over at once, and on most databases the memory cost
    9761             :  * isn't high.
    9762             :  *
    9763             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
    9764             :  */
    9765             : static int
    9766          98 : collectComments(Archive *fout, CommentItem **items)
    9767             : {
    9768             :     PGresult   *res;
    9769             :     PQExpBuffer query;
    9770             :     int         i_description;
    9771             :     int         i_classoid;
    9772             :     int         i_objoid;
    9773             :     int         i_objsubid;
    9774             :     int         ntups;
    9775             :     int         i;
    9776             :     CommentItem *comments;
    9777             : 
    9778          98 :     query = createPQExpBuffer();
    9779             : 
    9780          98 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
    9781             :                          "FROM pg_catalog.pg_description "
    9782             :                          "ORDER BY classoid, objoid, objsubid");
    9783             : 
    9784          98 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9785             : 
    9786             :     /* Construct lookup table containing OIDs in numeric form */
    9787             : 
    9788          98 :     i_description = PQfnumber(res, "description");
    9789          98 :     i_classoid = PQfnumber(res, "classoid");
    9790          98 :     i_objoid = PQfnumber(res, "objoid");
    9791          98 :     i_objsubid = PQfnumber(res, "objsubid");
    9792             : 
    9793          98 :     ntups = PQntuples(res);
    9794             : 
    9795          98 :     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
    9796             : 
    9797      395858 :     for (i = 0; i < ntups; i++)
    9798             :     {
    9799      395760 :         comments[i].descr = PQgetvalue(res, i, i_description);
    9800      395760 :         comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
    9801      395760 :         comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
    9802      395760 :         comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
    9803             :     }
    9804             : 
    9805             :     /* Do NOT free the PGresult since we are keeping pointers into it */
    9806          98 :     destroyPQExpBuffer(query);
    9807             : 
    9808          98 :     *items = comments;
    9809          98 :     return ntups;
    9810             : }
    9811             : 
    9812             : /*
    9813             :  * dumpDumpableObject
    9814             :  *
    9815             :  * This routine and its subsidiaries are responsible for creating
    9816             :  * ArchiveEntries (TOC objects) for each object to be dumped.
    9817             :  */
    9818             : static void
    9819      376430 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
    9820             : {
    9821      376430 :     switch (dobj->objType)
    9822             :     {
    9823             :         case DO_NAMESPACE:
    9824        1236 :             dumpNamespace(fout, (NamespaceInfo *) dobj);
    9825        1236 :             break;
    9826             :         case DO_EXTENSION:
    9827         188 :             dumpExtension(fout, (ExtensionInfo *) dobj);
    9828         188 :             break;
    9829             :         case DO_TYPE:
    9830       15690 :             dumpType(fout, (TypeInfo *) dobj);
    9831       15690 :             break;
    9832             :         case DO_SHELL_TYPE:
    9833        5610 :             dumpShellType(fout, (ShellTypeInfo *) dobj);
    9834        5610 :             break;
    9835             :         case DO_FUNC:
    9836        3772 :             dumpFunc(fout, (FuncInfo *) dobj);
    9837        3772 :             break;
    9838             :         case DO_AGG:
    9839         366 :             dumpAgg(fout, (AggInfo *) dobj);
    9840         366 :             break;
    9841             :         case DO_OPERATOR:
    9842      121520 :             dumpOpr(fout, (OprInfo *) dobj);
    9843      121520 :             break;
    9844             :         case DO_ACCESS_METHOD:
    9845        1246 :             dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
    9846        1246 :             break;
    9847             :         case DO_OPCLASS:
    9848       20154 :             dumpOpclass(fout, (OpclassInfo *) dobj);
    9849       20154 :             break;
    9850             :         case DO_OPFAMILY:
    9851       16838 :             dumpOpfamily(fout, (OpfamilyInfo *) dobj);
    9852       16838 :             break;
    9853             :         case DO_COLLATION:
    9854        1150 :             dumpCollation(fout, (CollInfo *) dobj);
    9855        1150 :             break;
    9856             :         case DO_CONVERSION:
    9857       20026 :             dumpConversion(fout, (ConvInfo *) dobj);
    9858       20026 :             break;
    9859             :         case DO_TABLE:
    9860       35580 :             dumpTable(fout, (TableInfo *) dobj);
    9861       35580 :             break;
    9862             :         case DO_ATTRDEF:
    9863         752 :             dumpAttrDef(fout, (AttrDefInfo *) dobj);
    9864         752 :             break;
    9865             :         case DO_INDEX:
    9866        1790 :             dumpIndex(fout, (IndxInfo *) dobj);
    9867        1790 :             break;
    9868             :         case DO_INDEX_ATTACH:
    9869         328 :             dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
    9870         328 :             break;
    9871             :         case DO_STATSEXT:
    9872         140 :             dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
    9873         140 :             break;
    9874             :         case DO_REFRESH_MATVIEW:
    9875         336 :             refreshMatViewData(fout, (TableDataInfo *) dobj);
    9876         336 :             break;
    9877             :         case DO_RULE:
    9878       20624 :             dumpRule(fout, (RuleInfo *) dobj);
    9879       20624 :             break;
    9880             :         case DO_TRIGGER:
    9881         392 :             dumpTrigger(fout, (TriggerInfo *) dobj);
    9882         392 :             break;
    9883             :         case DO_EVENT_TRIGGER:
    9884          58 :             dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
    9885          58 :             break;
    9886             :         case DO_CONSTRAINT:
    9887        1432 :             dumpConstraint(fout, (ConstraintInfo *) dobj);
    9888        1432 :             break;
    9889             :         case DO_FK_CONSTRAINT:
    9890         186 :             dumpConstraint(fout, (ConstraintInfo *) dobj);
    9891         186 :             break;
    9892             :         case DO_PROCLANG:
    9893         214 :             dumpProcLang(fout, (ProcLangInfo *) dobj);
    9894         214 :             break;
    9895             :         case DO_CAST:
    9896       33790 :             dumpCast(fout, (CastInfo *) dobj);
    9897       33790 :             break;
    9898             :         case DO_TRANSFORM:
    9899          64 :             dumpTransform(fout, (TransformInfo *) dobj);
    9900          64 :             break;
    9901             :         case DO_SEQUENCE_SET:
    9902         408 :             dumpSequenceData(fout, (TableDataInfo *) dobj);
    9903         408 :             break;
    9904             :         case DO_TABLE_DATA:
    9905        2534 :             dumpTableData(fout, (TableDataInfo *) dobj);
    9906        2534 :             break;
    9907             :         case DO_DUMMY_TYPE:
    9908             :             /* table rowtypes and array types are never dumped separately */
    9909       60168 :             break;
    9910             :         case DO_TSPARSER:
    9911         214 :             dumpTSParser(fout, (TSParserInfo *) dobj);
    9912         214 :             break;
    9913             :         case DO_TSDICT:
    9914        3700 :             dumpTSDictionary(fout, (TSDictInfo *) dobj);
    9915        3700 :             break;
    9916             :         case DO_TSTEMPLATE:
    9917         838 :             dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
    9918         838 :             break;
    9919             :         case DO_TSCONFIG:
    9920        3670 :             dumpTSConfig(fout, (TSConfigInfo *) dobj);
    9921        3670 :             break;
    9922             :         case DO_FDW:
    9923          64 :             dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
    9924          64 :             break;
    9925             :         case DO_FOREIGN_SERVER:
    9926          64 :             dumpForeignServer(fout, (ForeignServerInfo *) dobj);
    9927          64 :             break;
    9928             :         case DO_DEFAULT_ACL:
    9929         174 :             dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
    9930         174 :             break;
    9931             :         case DO_BLOB:
    9932          62 :             dumpBlob(fout, (BlobInfo *) dobj);
    9933          62 :             break;
    9934             :         case DO_BLOB_DATA:
    9935          50 :             if (dobj->dump & DUMP_COMPONENT_DATA)
    9936             :             {
    9937             :                 TocEntry   *te;
    9938             : 
    9939          50 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
    9940          50 :                                   ARCHIVE_OPTS(.tag = dobj->name,
    9941             :                                                .description = "BLOBS",
    9942             :                                                .section = SECTION_DATA,
    9943             :                                                .dumpFn = dumpBlobs));
    9944             : 
    9945             :                 /*
    9946             :                  * Set the TocEntry's dataLength in case we are doing a
    9947             :                  * parallel dump and want to order dump jobs by table size.
    9948             :                  * (We need some size estimate for every TocEntry with a
    9949             :                  * DataDumper function.)  We don't currently have any cheap
    9950             :                  * way to estimate the size of blobs, but it doesn't matter;
    9951             :                  * let's just set the size to a large value so parallel dumps
    9952             :                  * will launch this job first.  If there's lots of blobs, we
    9953             :                  * win, and if there aren't, we don't lose much.  (If you want
    9954             :                  * to improve on this, really what you should be thinking
    9955             :                  * about is allowing blob dumping to be parallelized, not just
    9956             :                  * getting a smarter estimate for the single TOC entry.)
    9957             :                  */
    9958          50 :                 te->dataLength = MaxBlockNumber;
    9959             :             }
    9960          50 :             break;
    9961             :         case DO_POLICY:
    9962         422 :             dumpPolicy(fout, (PolicyInfo *) dobj);
    9963         422 :             break;
    9964             :         case DO_PUBLICATION:
    9965         116 :             dumpPublication(fout, (PublicationInfo *) dobj);
    9966         116 :             break;
    9967             :         case DO_PUBLICATION_REL:
    9968          98 :             dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
    9969          98 :             break;
    9970             :         case DO_SUBSCRIPTION:
    9971          54 :             dumpSubscription(fout, (SubscriptionInfo *) dobj);
    9972          54 :             break;
    9973             :         case DO_PRE_DATA_BOUNDARY:
    9974             :         case DO_POST_DATA_BOUNDARY:
    9975             :             /* never dumped, nothing to do */
    9976         312 :             break;
    9977             :     }
    9978      376430 : }
    9979             : 
    9980             : /*
    9981             :  * dumpNamespace
    9982             :  *    writes out to fout the queries to recreate a user-defined namespace
    9983             :  */
    9984             : static void
    9985        1236 : dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
    9986             : {
    9987        1236 :     DumpOptions *dopt = fout->dopt;
    9988             :     PQExpBuffer q;
    9989             :     PQExpBuffer delq;
    9990             :     char       *qnspname;
    9991             : 
    9992             :     /* Skip if not to be dumped */
    9993        1236 :     if (!nspinfo->dobj.dump || dopt->dataOnly)
    9994        1020 :         return;
    9995             : 
    9996         216 :     q = createPQExpBuffer();
    9997         216 :     delq = createPQExpBuffer();
    9998             : 
    9999         216 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   10000             : 
   10001         216 :     appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   10002             : 
   10003         216 :     appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   10004             : 
   10005         216 :     if (dopt->binary_upgrade)
   10006          26 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   10007             :                                         "SCHEMA", qnspname, NULL);
   10008             : 
   10009         216 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   10010         146 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   10011         146 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   10012             :                                   .owner = nspinfo->rolname,
   10013             :                                   .description = "SCHEMA",
   10014             :                                   .section = SECTION_PRE_DATA,
   10015             :                                   .createStmt = q->data,
   10016             :                                   .dropStmt = delq->data));
   10017             : 
   10018             :     /* Dump Schema Comments and Security Labels */
   10019         216 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   10020         292 :         dumpComment(fout, "SCHEMA", qnspname,
   10021         146 :                     NULL, nspinfo->rolname,
   10022             :                     nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   10023             : 
   10024         216 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   10025         348 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   10026         174 :                      NULL, nspinfo->rolname,
   10027             :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   10028             : 
   10029         216 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   10030          88 :         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
   10031             :                 qnspname, NULL, NULL,
   10032          88 :                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
   10033          88 :                 nspinfo->initnspacl, nspinfo->initrnspacl);
   10034             : 
   10035         216 :     free(qnspname);
   10036             : 
   10037         216 :     destroyPQExpBuffer(q);
   10038         216 :     destroyPQExpBuffer(delq);
   10039             : }
   10040             : 
   10041             : /*
   10042             :  * dumpExtension
   10043             :  *    writes out to fout the queries to recreate an extension
   10044             :  */
   10045             : static void
   10046         188 : dumpExtension(Archive *fout, ExtensionInfo *extinfo)
   10047             : {
   10048         188 :     DumpOptions *dopt = fout->dopt;
   10049             :     PQExpBuffer q;
   10050             :     PQExpBuffer delq;
   10051             :     char       *qextname;
   10052             : 
   10053             :     /* Skip if not to be dumped */
   10054         188 :     if (!extinfo->dobj.dump || dopt->dataOnly)
   10055          10 :         return;
   10056             : 
   10057         178 :     q = createPQExpBuffer();
   10058         178 :     delq = createPQExpBuffer();
   10059             : 
   10060         178 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   10061             : 
   10062         178 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   10063             : 
   10064         178 :     if (!dopt->binary_upgrade)
   10065             :     {
   10066             :         /*
   10067             :          * In a regular dump, we simply create the extension, intentionally
   10068             :          * not specifying a version, so that the destination installation's
   10069             :          * default version is used.
   10070             :          *
   10071             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   10072             :          * types; but there are various scenarios in which it's convenient to
   10073             :          * manually create the desired extension before restoring, so we
   10074             :          * prefer to allow it to exist already.
   10075             :          */
   10076         160 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EX