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