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