LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 6844 7580 90.3 %
Date: 2024-05-09 17:10:46 Functions: 172 176 97.7 %
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-2024, 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 "common/relpath.h"
      59             : #include "compress_io.h"
      60             : #include "dumputils.h"
      61             : #include "fe_utils/option_utils.h"
      62             : #include "fe_utils/string_utils.h"
      63             : #include "filter.h"
      64             : #include "getopt_long.h"
      65             : #include "libpq/libpq-fs.h"
      66             : #include "parallel.h"
      67             : #include "pg_backup_db.h"
      68             : #include "pg_backup_utils.h"
      69             : #include "pg_dump.h"
      70             : #include "storage/block.h"
      71             : 
      72             : typedef struct
      73             : {
      74             :     Oid         roleoid;        /* role's OID */
      75             :     const char *rolename;       /* role's name */
      76             : } RoleNameItem;
      77             : 
      78             : typedef struct
      79             : {
      80             :     const char *descr;          /* comment for an object */
      81             :     Oid         classoid;       /* object class (catalog OID) */
      82             :     Oid         objoid;         /* object OID */
      83             :     int         objsubid;       /* subobject (table column #) */
      84             : } CommentItem;
      85             : 
      86             : typedef struct
      87             : {
      88             :     const char *provider;       /* label provider of this security label */
      89             :     const char *label;          /* security label for an object */
      90             :     Oid         classoid;       /* object class (catalog OID) */
      91             :     Oid         objoid;         /* object OID */
      92             :     int         objsubid;       /* subobject (table column #) */
      93             : } SecLabelItem;
      94             : 
      95             : typedef enum OidOptions
      96             : {
      97             :     zeroIsError = 1,
      98             :     zeroAsStar = 2,
      99             :     zeroAsNone = 4,
     100             : } OidOptions;
     101             : 
     102             : /* global decls */
     103             : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     104             : 
     105             : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     106             : 
     107             : /* The specified names/patterns should to match at least one entity */
     108             : static int  strict_names = 0;
     109             : 
     110             : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     111             : 
     112             : /*
     113             :  * Object inclusion/exclusion lists
     114             :  *
     115             :  * The string lists record the patterns given by command-line switches,
     116             :  * which we then convert to lists of OIDs of matching objects.
     117             :  */
     118             : static SimpleStringList schema_include_patterns = {NULL, NULL};
     119             : static SimpleOidList schema_include_oids = {NULL, NULL};
     120             : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     121             : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     122             : 
     123             : static SimpleStringList table_include_patterns = {NULL, NULL};
     124             : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     125             : static SimpleOidList table_include_oids = {NULL, NULL};
     126             : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     127             : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     128             : static SimpleOidList table_exclude_oids = {NULL, NULL};
     129             : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     130             : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     131             : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     132             : 
     133             : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     134             : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     135             : 
     136             : static SimpleStringList extension_include_patterns = {NULL, NULL};
     137             : static SimpleOidList extension_include_oids = {NULL, NULL};
     138             : 
     139             : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     140             : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     141             : 
     142             : static const CatalogId nilCatalogId = {0, 0};
     143             : 
     144             : /* override for standard extra_float_digits setting */
     145             : static bool have_extra_float_digits = false;
     146             : static int  extra_float_digits;
     147             : 
     148             : /* sorted table of role names */
     149             : static RoleNameItem *rolenames = NULL;
     150             : static int  nrolenames = 0;
     151             : 
     152             : /* sorted table of comments */
     153             : static CommentItem *comments = NULL;
     154             : static int  ncomments = 0;
     155             : 
     156             : /* sorted table of security labels */
     157             : static SecLabelItem *seclabels = NULL;
     158             : static int  nseclabels = 0;
     159             : 
     160             : /*
     161             :  * The default number of rows per INSERT when
     162             :  * --inserts is specified without --rows-per-insert
     163             :  */
     164             : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     165             : 
     166             : /*
     167             :  * Maximum number of large objects to group into a single ArchiveEntry.
     168             :  * At some point we might want to make this user-controllable, but for now
     169             :  * a hard-wired setting will suffice.
     170             :  */
     171             : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     172             : 
     173             : /*
     174             :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     175             :  */
     176             : #define fmtQualifiedDumpable(obj) \
     177             :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     178             :                    (obj)->dobj.name)
     179             : 
     180             : static void help(const char *progname);
     181             : static void setup_connection(Archive *AH,
     182             :                              const char *dumpencoding, const char *dumpsnapshot,
     183             :                              char *use_role);
     184             : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     185             : static void expand_schema_name_patterns(Archive *fout,
     186             :                                         SimpleStringList *patterns,
     187             :                                         SimpleOidList *oids,
     188             :                                         bool strict_names);
     189             : static void expand_extension_name_patterns(Archive *fout,
     190             :                                            SimpleStringList *patterns,
     191             :                                            SimpleOidList *oids,
     192             :                                            bool strict_names);
     193             : static void expand_foreign_server_name_patterns(Archive *fout,
     194             :                                                 SimpleStringList *patterns,
     195             :                                                 SimpleOidList *oids);
     196             : static void expand_table_name_patterns(Archive *fout,
     197             :                                        SimpleStringList *patterns,
     198             :                                        SimpleOidList *oids,
     199             :                                        bool strict_names,
     200             :                                        bool with_child_tables);
     201             : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     202             :                                   const char *pattern);
     203             : 
     204             : static NamespaceInfo *findNamespace(Oid nsoid);
     205             : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     206             : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     207             : static const char *getRoleName(const char *roleoid_str);
     208             : static void collectRoleNames(Archive *fout);
     209             : static void getAdditionalACLs(Archive *fout);
     210             : static void dumpCommentExtended(Archive *fout, const char *type,
     211             :                                 const char *name, const char *namespace,
     212             :                                 const char *owner, CatalogId catalogId,
     213             :                                 int subid, DumpId dumpId,
     214             :                                 const char *initdb_comment);
     215             : static inline void dumpComment(Archive *fout, const char *type,
     216             :                                const char *name, const char *namespace,
     217             :                                const char *owner, CatalogId catalogId,
     218             :                                int subid, DumpId dumpId);
     219             : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     220             : static void collectComments(Archive *fout);
     221             : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     222             :                          const char *namespace, const char *owner,
     223             :                          CatalogId catalogId, int subid, DumpId dumpId);
     224             : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     225             : static void collectSecLabels(Archive *fout);
     226             : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     227             : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     228             : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     229             : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     230             : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     231             : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     232             : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     233             : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     234             : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     235             : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     236             : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     237             :                                          PGresult *res);
     238             : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     239             : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     240             : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     241             : static void dumpCast(Archive *fout, const CastInfo *cast);
     242             : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     243             : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     244             : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     245             : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     246             : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     247             : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     248             : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     249             : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     250             : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     251             : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     252             : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     253             : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     254             : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     255             : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     256             : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     257             : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     258             : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     259             : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     260             : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     261             : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     262             : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     263             : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     264             : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     265             : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     266             : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     267             : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     268             : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     269             : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     270             : static void dumpUserMappings(Archive *fout,
     271             :                              const char *servername, const char *namespace,
     272             :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     273             : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     274             : 
     275             : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     276             :                       const char *type, const char *name, const char *subname,
     277             :                       const char *nspname, const char *tag, const char *owner,
     278             :                       const DumpableAcl *dacl);
     279             : 
     280             : static void getDependencies(Archive *fout);
     281             : static void BuildArchiveDependencies(Archive *fout);
     282             : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     283             :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     284             : 
     285             : static DumpableObject *createBoundaryObjects(void);
     286             : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     287             :                                     DumpableObject *boundaryObjs);
     288             : 
     289             : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     290             : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     291             : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     292             : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     293             : static void buildMatViewRefreshDependencies(Archive *fout);
     294             : static void getTableDataFKConstraints(void);
     295             : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     296             :                                        bool is_agg);
     297             : static char *format_function_signature(Archive *fout,
     298             :                                        const FuncInfo *finfo, bool honor_quotes);
     299             : static char *convertRegProcReference(const char *proc);
     300             : static char *getFormattedOperatorName(const char *oproid);
     301             : static char *convertTSFunction(Archive *fout, Oid funcOid);
     302             : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     303             : static void getLOs(Archive *fout);
     304             : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     305             : static int  dumpLOs(Archive *fout, const void *arg);
     306             : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     307             : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     308             : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     309             : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     310             : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     311             : static void dumpDatabase(Archive *fout);
     312             : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     313             :                                const char *dbname, Oid dboid);
     314             : static void dumpEncoding(Archive *AH);
     315             : static void dumpStdStrings(Archive *AH);
     316             : static void dumpSearchPath(Archive *AH);
     317             : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     318             :                                                      PQExpBuffer upgrade_buffer,
     319             :                                                      Oid pg_type_oid,
     320             :                                                      bool force_array_type,
     321             :                                                      bool include_multirange_type);
     322             : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     323             :                                                 PQExpBuffer upgrade_buffer,
     324             :                                                 const TableInfo *tbinfo);
     325             : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     326             :                                              PQExpBuffer upgrade_buffer,
     327             :                                              Oid pg_class_oid, bool is_index);
     328             : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     329             :                                             const DumpableObject *dobj,
     330             :                                             const char *objtype,
     331             :                                             const char *objname,
     332             :                                             const char *objnamespace);
     333             : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     334             : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     335             : static bool nonemptyReloptions(const char *reloptions);
     336             : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     337             :                                     const char *prefix, Archive *fout);
     338             : static char *get_synchronized_snapshot(Archive *fout);
     339             : static void setupDumpWorker(Archive *AH);
     340             : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     341             : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     342             : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     343             : 
     344             : 
     345             : int
     346         482 : main(int argc, char **argv)
     347             : {
     348             :     int         c;
     349         482 :     const char *filename = NULL;
     350         482 :     const char *format = "p";
     351             :     TableInfo  *tblinfo;
     352             :     int         numTables;
     353             :     DumpableObject **dobjs;
     354             :     int         numObjs;
     355             :     DumpableObject *boundaryObjs;
     356             :     int         i;
     357             :     int         optindex;
     358             :     RestoreOptions *ropt;
     359             :     Archive    *fout;           /* the script file */
     360         482 :     bool        g_verbose = false;
     361         482 :     const char *dumpencoding = NULL;
     362         482 :     const char *dumpsnapshot = NULL;
     363         482 :     char       *use_role = NULL;
     364         482 :     int         numWorkers = 1;
     365         482 :     int         plainText = 0;
     366         482 :     ArchiveFormat archiveFormat = archUnknown;
     367             :     ArchiveMode archiveMode;
     368         482 :     pg_compress_specification compression_spec = {0};
     369         482 :     char       *compression_detail = NULL;
     370         482 :     char       *compression_algorithm_str = "none";
     371         482 :     char       *error_detail = NULL;
     372         482 :     bool        user_compression_defined = false;
     373         482 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     374             : 
     375             :     static DumpOptions dopt;
     376             : 
     377             :     static struct option long_options[] = {
     378             :         {"data-only", no_argument, NULL, 'a'},
     379             :         {"blobs", no_argument, NULL, 'b'},
     380             :         {"large-objects", no_argument, NULL, 'b'},
     381             :         {"no-blobs", no_argument, NULL, 'B'},
     382             :         {"no-large-objects", no_argument, NULL, 'B'},
     383             :         {"clean", no_argument, NULL, 'c'},
     384             :         {"create", no_argument, NULL, 'C'},
     385             :         {"dbname", required_argument, NULL, 'd'},
     386             :         {"extension", required_argument, NULL, 'e'},
     387             :         {"file", required_argument, NULL, 'f'},
     388             :         {"format", required_argument, NULL, 'F'},
     389             :         {"host", required_argument, NULL, 'h'},
     390             :         {"jobs", 1, NULL, 'j'},
     391             :         {"no-reconnect", no_argument, NULL, 'R'},
     392             :         {"no-owner", no_argument, NULL, 'O'},
     393             :         {"port", required_argument, NULL, 'p'},
     394             :         {"schema", required_argument, NULL, 'n'},
     395             :         {"exclude-schema", required_argument, NULL, 'N'},
     396             :         {"schema-only", no_argument, NULL, 's'},
     397             :         {"superuser", required_argument, NULL, 'S'},
     398             :         {"table", required_argument, NULL, 't'},
     399             :         {"exclude-table", required_argument, NULL, 'T'},
     400             :         {"no-password", no_argument, NULL, 'w'},
     401             :         {"password", no_argument, NULL, 'W'},
     402             :         {"username", required_argument, NULL, 'U'},
     403             :         {"verbose", no_argument, NULL, 'v'},
     404             :         {"no-privileges", no_argument, NULL, 'x'},
     405             :         {"no-acl", no_argument, NULL, 'x'},
     406             :         {"compress", required_argument, NULL, 'Z'},
     407             :         {"encoding", required_argument, NULL, 'E'},
     408             :         {"help", no_argument, NULL, '?'},
     409             :         {"version", no_argument, NULL, 'V'},
     410             : 
     411             :         /*
     412             :          * the following options don't have an equivalent short option letter
     413             :          */
     414             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     415             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     416             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     417             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     418             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     419             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     420             :         {"exclude-table-data", required_argument, NULL, 4},
     421             :         {"extra-float-digits", required_argument, NULL, 8},
     422             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     423             :         {"inserts", no_argument, NULL, 9},
     424             :         {"lock-wait-timeout", required_argument, NULL, 2},
     425             :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     426             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     427             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     428             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     429             :         {"role", required_argument, NULL, 3},
     430             :         {"section", required_argument, NULL, 5},
     431             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     432             :         {"snapshot", required_argument, NULL, 6},
     433             :         {"strict-names", no_argument, &strict_names, 1},
     434             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     435             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     436             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     437             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     438             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     439             :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     440             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     441             :         {"no-sync", no_argument, NULL, 7},
     442             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     443             :         {"rows-per-insert", required_argument, NULL, 10},
     444             :         {"include-foreign-data", required_argument, NULL, 11},
     445             :         {"table-and-children", required_argument, NULL, 12},
     446             :         {"exclude-table-and-children", required_argument, NULL, 13},
     447             :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     448             :         {"sync-method", required_argument, NULL, 15},
     449             :         {"filter", required_argument, NULL, 16},
     450             :         {"exclude-extension", required_argument, NULL, 17},
     451             : 
     452             :         {NULL, 0, NULL, 0}
     453             :     };
     454             : 
     455         482 :     pg_logging_init(argv[0]);
     456         482 :     pg_logging_set_level(PG_LOG_WARNING);
     457         482 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     458             : 
     459             :     /*
     460             :      * Initialize what we need for parallel execution, especially for thread
     461             :      * support on Windows.
     462             :      */
     463         482 :     init_parallel_dump_utils();
     464             : 
     465         482 :     progname = get_progname(argv[0]);
     466             : 
     467         482 :     if (argc > 1)
     468             :     {
     469         482 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     470             :         {
     471           2 :             help(progname);
     472           2 :             exit_nicely(0);
     473             :         }
     474         480 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     475             :         {
     476          94 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     477          94 :             exit_nicely(0);
     478             :         }
     479             :     }
     480             : 
     481         386 :     InitDumpOptions(&dopt);
     482             : 
     483        1666 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
     484             :                             long_options, &optindex)) != -1)
     485             :     {
     486        1296 :         switch (c)
     487             :         {
     488          16 :             case 'a':           /* Dump data only */
     489          16 :                 dopt.dataOnly = true;
     490          16 :                 break;
     491             : 
     492           2 :             case 'b':           /* Dump LOs */
     493           2 :                 dopt.outputLOs = true;
     494           2 :                 break;
     495             : 
     496           4 :             case 'B':           /* Don't dump LOs */
     497           4 :                 dopt.dontOutputLOs = true;
     498           4 :                 break;
     499             : 
     500          12 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     501          12 :                 dopt.outputClean = 1;
     502          12 :                 break;
     503             : 
     504          58 :             case 'C':           /* Create DB */
     505          58 :                 dopt.outputCreateDB = 1;
     506          58 :                 break;
     507             : 
     508          10 :             case 'd':           /* database name */
     509          10 :                 dopt.cparams.dbname = pg_strdup(optarg);
     510          10 :                 break;
     511             : 
     512           8 :             case 'e':           /* include extension(s) */
     513           8 :                 simple_string_list_append(&extension_include_patterns, optarg);
     514           8 :                 dopt.include_everything = false;
     515           8 :                 break;
     516             : 
     517           4 :             case 'E':           /* Dump encoding */
     518           4 :                 dumpencoding = pg_strdup(optarg);
     519           4 :                 break;
     520             : 
     521         302 :             case 'f':
     522         302 :                 filename = pg_strdup(optarg);
     523         302 :                 break;
     524             : 
     525         170 :             case 'F':
     526         170 :                 format = pg_strdup(optarg);
     527         170 :                 break;
     528             : 
     529          24 :             case 'h':           /* server host */
     530          24 :                 dopt.cparams.pghost = pg_strdup(optarg);
     531          24 :                 break;
     532             : 
     533          22 :             case 'j':           /* number of dump jobs */
     534          22 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     535             :                                       PG_MAX_JOBS,
     536             :                                       &numWorkers))
     537           2 :                     exit_nicely(1);
     538          20 :                 break;
     539             : 
     540          30 :             case 'n':           /* include schema(s) */
     541          30 :                 simple_string_list_append(&schema_include_patterns, optarg);
     542          30 :                 dopt.include_everything = false;
     543          30 :                 break;
     544             : 
     545           2 :             case 'N':           /* exclude schema(s) */
     546           2 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     547           2 :                 break;
     548             : 
     549           4 :             case 'O':           /* Don't reconnect to match owner */
     550           4 :                 dopt.outputNoOwner = 1;
     551           4 :                 break;
     552             : 
     553          96 :             case 'p':           /* server port */
     554          96 :                 dopt.cparams.pgport = pg_strdup(optarg);
     555          96 :                 break;
     556             : 
     557           4 :             case 'R':
     558             :                 /* no-op, still accepted for backwards compatibility */
     559           4 :                 break;
     560             : 
     561          36 :             case 's':           /* dump schema only */
     562          36 :                 dopt.schemaOnly = true;
     563          36 :                 break;
     564             : 
     565           2 :             case 'S':           /* Username for superuser in plain text output */
     566           2 :                 dopt.outputSuperuser = pg_strdup(optarg);
     567           2 :                 break;
     568             : 
     569          16 :             case 't':           /* include table(s) */
     570          16 :                 simple_string_list_append(&table_include_patterns, optarg);
     571          16 :                 dopt.include_everything = false;
     572          16 :                 break;
     573             : 
     574           8 :             case 'T':           /* exclude table(s) */
     575           8 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     576           8 :                 break;
     577             : 
     578          28 :             case 'U':
     579          28 :                 dopt.cparams.username = pg_strdup(optarg);
     580          28 :                 break;
     581             : 
     582          12 :             case 'v':           /* verbose */
     583          12 :                 g_verbose = true;
     584          12 :                 pg_logging_increase_verbosity();
     585          12 :                 break;
     586             : 
     587           2 :             case 'w':
     588           2 :                 dopt.cparams.promptPassword = TRI_NO;
     589           2 :                 break;
     590             : 
     591           0 :             case 'W':
     592           0 :                 dopt.cparams.promptPassword = TRI_YES;
     593           0 :                 break;
     594             : 
     595           4 :             case 'x':           /* skip ACL dump */
     596           4 :                 dopt.aclsSkip = true;
     597           4 :                 break;
     598             : 
     599          24 :             case 'Z':           /* Compression */
     600          24 :                 parse_compress_options(optarg, &compression_algorithm_str,
     601             :                                        &compression_detail);
     602          24 :                 user_compression_defined = true;
     603          24 :                 break;
     604             : 
     605          98 :             case 0:
     606             :                 /* This covers the long options. */
     607          98 :                 break;
     608             : 
     609           4 :             case 2:             /* lock-wait-timeout */
     610           4 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     611           4 :                 break;
     612             : 
     613           6 :             case 3:             /* SET ROLE */
     614           6 :                 use_role = pg_strdup(optarg);
     615           6 :                 break;
     616             : 
     617           2 :             case 4:             /* exclude table(s) data */
     618           2 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     619           2 :                 break;
     620             : 
     621          12 :             case 5:             /* section */
     622          12 :                 set_dump_section(optarg, &dopt.dumpSections);
     623          12 :                 break;
     624             : 
     625           0 :             case 6:             /* snapshot */
     626           0 :                 dumpsnapshot = pg_strdup(optarg);
     627           0 :                 break;
     628             : 
     629         194 :             case 7:             /* no-sync */
     630         194 :                 dosync = false;
     631         194 :                 break;
     632             : 
     633           2 :             case 8:
     634           2 :                 have_extra_float_digits = true;
     635           2 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     636             :                                       &extra_float_digits))
     637           2 :                     exit_nicely(1);
     638           0 :                 break;
     639             : 
     640           4 :             case 9:             /* inserts */
     641             : 
     642             :                 /*
     643             :                  * dump_inserts also stores --rows-per-insert, careful not to
     644             :                  * overwrite that.
     645             :                  */
     646           4 :                 if (dopt.dump_inserts == 0)
     647           4 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     648           4 :                 break;
     649             : 
     650           4 :             case 10:            /* rows per insert */
     651           4 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     652             :                                       &dopt.dump_inserts))
     653           2 :                     exit_nicely(1);
     654           2 :                 break;
     655             : 
     656           8 :             case 11:            /* include foreign data */
     657           8 :                 simple_string_list_append(&foreign_servers_include_patterns,
     658             :                                           optarg);
     659           8 :                 break;
     660             : 
     661           2 :             case 12:            /* include table(s) and their children */
     662           2 :                 simple_string_list_append(&table_include_patterns_and_children,
     663             :                                           optarg);
     664           2 :                 dopt.include_everything = false;
     665           2 :                 break;
     666             : 
     667           2 :             case 13:            /* exclude table(s) and their children */
     668           2 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     669             :                                           optarg);
     670           2 :                 break;
     671             : 
     672           2 :             case 14:            /* exclude data of table(s) and children */
     673           2 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     674             :                                           optarg);
     675           2 :                 break;
     676             : 
     677           0 :             case 15:
     678           0 :                 if (!parse_sync_method(optarg, &sync_method))
     679           0 :                     exit_nicely(1);
     680           0 :                 break;
     681             : 
     682          52 :             case 16:            /* read object filters from file */
     683          52 :                 read_dump_filters(optarg, &dopt);
     684          44 :                 break;
     685             : 
     686           2 :             case 17:            /* exclude extension(s) */
     687           2 :                 simple_string_list_append(&extension_exclude_patterns,
     688             :                                           optarg);
     689           2 :                 break;
     690             : 
     691           2 :             default:
     692             :                 /* getopt_long already emitted a complaint */
     693           2 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     694           2 :                 exit_nicely(1);
     695             :         }
     696             :     }
     697             : 
     698             :     /*
     699             :      * Non-option argument specifies database name as long as it wasn't
     700             :      * already specified with -d / --dbname
     701             :      */
     702         370 :     if (optind < argc && dopt.cparams.dbname == NULL)
     703         306 :         dopt.cparams.dbname = argv[optind++];
     704             : 
     705             :     /* Complain if any arguments remain */
     706         370 :     if (optind < argc)
     707             :     {
     708           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     709             :                      argv[optind]);
     710           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     711           2 :         exit_nicely(1);
     712             :     }
     713             : 
     714             :     /* --column-inserts implies --inserts */
     715         368 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     716           2 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     717             : 
     718             :     /*
     719             :      * Binary upgrade mode implies dumping sequence data even in schema-only
     720             :      * mode.  This is not exposed as a separate option, but kept separate
     721             :      * internally for clarity.
     722             :      */
     723         368 :     if (dopt.binary_upgrade)
     724          28 :         dopt.sequence_data = 1;
     725             : 
     726         368 :     if (dopt.dataOnly && dopt.schemaOnly)
     727           2 :         pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
     728             : 
     729         366 :     if (dopt.schemaOnly && foreign_servers_include_patterns.head != NULL)
     730           2 :         pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
     731             : 
     732         364 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     733           2 :         pg_fatal("option --include-foreign-data is not supported with parallel backup");
     734             : 
     735         362 :     if (dopt.dataOnly && dopt.outputClean)
     736           2 :         pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
     737             : 
     738         360 :     if (dopt.if_exists && !dopt.outputClean)
     739           2 :         pg_fatal("option --if-exists requires option -c/--clean");
     740             : 
     741             :     /*
     742             :      * --inserts are already implied above if --column-inserts or
     743             :      * --rows-per-insert were specified.
     744             :      */
     745         358 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     746           2 :         pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
     747             : 
     748             :     /* Identify archive format to emit */
     749         356 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     750             : 
     751             :     /* archiveFormat specific setup */
     752         354 :     if (archiveFormat == archNull)
     753         290 :         plainText = 1;
     754             : 
     755             :     /*
     756             :      * Custom and directory formats are compressed by default with gzip when
     757             :      * available, not the others.  If gzip is not available, no compression is
     758             :      * done by default.
     759             :      */
     760         354 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     761          58 :         !user_compression_defined)
     762             :     {
     763             : #ifdef HAVE_LIBZ
     764          48 :         compression_algorithm_str = "gzip";
     765             : #else
     766             :         compression_algorithm_str = "none";
     767             : #endif
     768             :     }
     769             : 
     770             :     /*
     771             :      * Compression options
     772             :      */
     773         354 :     if (!parse_compress_algorithm(compression_algorithm_str,
     774             :                                   &compression_algorithm))
     775           2 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     776             :                  compression_algorithm_str);
     777             : 
     778         352 :     parse_compress_specification(compression_algorithm, compression_detail,
     779             :                                  &compression_spec);
     780         352 :     error_detail = validate_compress_specification(&compression_spec);
     781         352 :     if (error_detail != NULL)
     782           6 :         pg_fatal("invalid compression specification: %s",
     783             :                  error_detail);
     784             : 
     785         346 :     error_detail = supports_compression(compression_spec);
     786         346 :     if (error_detail != NULL)
     787           0 :         pg_fatal("%s", error_detail);
     788             : 
     789             :     /*
     790             :      * Disable support for zstd workers for now - these are based on
     791             :      * threading, and it's unclear how it interacts with parallel dumps on
     792             :      * platforms where that relies on threads too (e.g. Windows).
     793             :      */
     794         346 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     795           0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     796             :                        "workers");
     797             : 
     798             :     /*
     799             :      * If emitting an archive format, we always want to emit a DATABASE item,
     800             :      * in case --create is specified at pg_restore time.
     801             :      */
     802         346 :     if (!plainText)
     803          64 :         dopt.outputCreateDB = 1;
     804             : 
     805             :     /* Parallel backup only in the directory archive format so far */
     806         346 :     if (archiveFormat != archDirectory && numWorkers > 1)
     807           2 :         pg_fatal("parallel backup only supported by the directory format");
     808             : 
     809             :     /* Open the output file */
     810         344 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     811             :                          dosync, archiveMode, setupDumpWorker, sync_method);
     812             : 
     813             :     /* Make dump options accessible right away */
     814         342 :     SetArchiveOptions(fout, &dopt, NULL);
     815             : 
     816             :     /* Register the cleanup hook */
     817         342 :     on_exit_close_archive(fout);
     818             : 
     819             :     /* Let the archiver know how noisy to be */
     820         342 :     fout->verbose = g_verbose;
     821             : 
     822             : 
     823             :     /*
     824             :      * We allow the server to be back to 9.2, and up to any minor release of
     825             :      * our own major version.  (See also version check in pg_dumpall.c.)
     826             :      */
     827         342 :     fout->minRemoteVersion = 90200;
     828         342 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     829             : 
     830         342 :     fout->numWorkers = numWorkers;
     831             : 
     832             :     /*
     833             :      * Open the database using the Archiver, so it knows about it. Errors mean
     834             :      * death.
     835             :      */
     836         342 :     ConnectDatabase(fout, &dopt.cparams, false);
     837         338 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     838             : 
     839             :     /*
     840             :      * On hot standbys, never try to dump unlogged table data, since it will
     841             :      * just throw an error.
     842             :      */
     843         338 :     if (fout->isStandby)
     844           6 :         dopt.no_unlogged_table_data = true;
     845             : 
     846             :     /*
     847             :      * Find the last built-in OID, if needed (prior to 8.1)
     848             :      *
     849             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
     850             :      */
     851         338 :     g_last_builtin_oid = FirstNormalObjectId - 1;
     852             : 
     853         338 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
     854             : 
     855             :     /* Expand schema selection patterns into OID lists */
     856         338 :     if (schema_include_patterns.head != NULL)
     857             :     {
     858          32 :         expand_schema_name_patterns(fout, &schema_include_patterns,
     859             :                                     &schema_include_oids,
     860             :                                     strict_names);
     861          20 :         if (schema_include_oids.head == NULL)
     862           2 :             pg_fatal("no matching schemas were found");
     863             :     }
     864         324 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
     865             :                                 &schema_exclude_oids,
     866             :                                 false);
     867             :     /* non-matching exclusion patterns aren't an error */
     868             : 
     869             :     /* Expand table selection patterns into OID lists */
     870         324 :     expand_table_name_patterns(fout, &table_include_patterns,
     871             :                                &table_include_oids,
     872             :                                strict_names, false);
     873         314 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
     874             :                                &table_include_oids,
     875             :                                strict_names, true);
     876         314 :     if ((table_include_patterns.head != NULL ||
     877         292 :          table_include_patterns_and_children.head != NULL) &&
     878          26 :         table_include_oids.head == NULL)
     879           4 :         pg_fatal("no matching tables were found");
     880             : 
     881         310 :     expand_table_name_patterns(fout, &table_exclude_patterns,
     882             :                                &table_exclude_oids,
     883             :                                false, false);
     884         310 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
     885             :                                &table_exclude_oids,
     886             :                                false, true);
     887             : 
     888         310 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
     889             :                                &tabledata_exclude_oids,
     890             :                                false, false);
     891         310 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
     892             :                                &tabledata_exclude_oids,
     893             :                                false, true);
     894             : 
     895         310 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
     896             :                                         &foreign_servers_include_oids);
     897             : 
     898             :     /* non-matching exclusion patterns aren't an error */
     899             : 
     900             :     /* Expand extension selection patterns into OID lists */
     901         308 :     if (extension_include_patterns.head != NULL)
     902             :     {
     903          10 :         expand_extension_name_patterns(fout, &extension_include_patterns,
     904             :                                        &extension_include_oids,
     905             :                                        strict_names);
     906          10 :         if (extension_include_oids.head == NULL)
     907           2 :             pg_fatal("no matching extensions were found");
     908             :     }
     909         306 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
     910             :                                    &extension_exclude_oids,
     911             :                                    false);
     912             :     /* non-matching exclusion patterns aren't an error */
     913             : 
     914             :     /*
     915             :      * Dumping LOs is the default for dumps where an inclusion switch is not
     916             :      * used (an "include everything" dump).  -B can be used to exclude LOs
     917             :      * from those dumps.  -b can be used to include LOs even when an inclusion
     918             :      * switch is used.
     919             :      *
     920             :      * -s means "schema only" and LOs are data, not schema, so we never
     921             :      * include LOs when -s is used.
     922             :      */
     923         306 :     if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputLOs)
     924         228 :         dopt.outputLOs = true;
     925             : 
     926             :     /*
     927             :      * Collect role names so we can map object owner OIDs to names.
     928             :      */
     929         306 :     collectRoleNames(fout);
     930             : 
     931             :     /*
     932             :      * Now scan the database and create DumpableObject structs for all the
     933             :      * objects we intend to dump.
     934             :      */
     935         306 :     tblinfo = getSchemaData(fout, &numTables);
     936             : 
     937         304 :     if (!dopt.schemaOnly)
     938             :     {
     939         272 :         getTableData(&dopt, tblinfo, numTables, 0);
     940         272 :         buildMatViewRefreshDependencies(fout);
     941         272 :         if (dopt.dataOnly)
     942          12 :             getTableDataFKConstraints();
     943             :     }
     944             : 
     945         304 :     if (dopt.schemaOnly && dopt.sequence_data)
     946          28 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
     947             : 
     948             :     /*
     949             :      * In binary-upgrade mode, we do not have to worry about the actual LO
     950             :      * data or the associated metadata that resides in the pg_largeobject and
     951             :      * pg_largeobject_metadata tables, respectively.
     952             :      *
     953             :      * However, we do need to collect LO information as there may be comments
     954             :      * or other information on LOs that we do need to dump out.
     955             :      */
     956         304 :     if (dopt.outputLOs || dopt.binary_upgrade)
     957         256 :         getLOs(fout);
     958             : 
     959             :     /*
     960             :      * Collect dependency data to assist in ordering the objects.
     961             :      */
     962         304 :     getDependencies(fout);
     963             : 
     964             :     /*
     965             :      * Collect ACLs, comments, and security labels, if wanted.
     966             :      */
     967         304 :     if (!dopt.aclsSkip)
     968         300 :         getAdditionalACLs(fout);
     969         304 :     if (!dopt.no_comments)
     970         304 :         collectComments(fout);
     971         304 :     if (!dopt.no_security_labels)
     972         304 :         collectSecLabels(fout);
     973             : 
     974             :     /* Lastly, create dummy objects to represent the section boundaries */
     975         304 :     boundaryObjs = createBoundaryObjects();
     976             : 
     977             :     /* Get pointers to all the known DumpableObjects */
     978         304 :     getDumpableObjects(&dobjs, &numObjs);
     979             : 
     980             :     /*
     981             :      * Add dummy dependencies to enforce the dump section ordering.
     982             :      */
     983         304 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
     984             : 
     985             :     /*
     986             :      * Sort the objects into a safe dump order (no forward references).
     987             :      *
     988             :      * We rely on dependency information to help us determine a safe order, so
     989             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
     990             :      * ensure that logically identical schemas will dump identically.
     991             :      */
     992         304 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
     993             : 
     994         304 :     sortDumpableObjects(dobjs, numObjs,
     995         304 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
     996             : 
     997             :     /*
     998             :      * Create archive TOC entries for all the objects to be dumped, in a safe
     999             :      * order.
    1000             :      */
    1001             : 
    1002             :     /*
    1003             :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1004             :      */
    1005         304 :     dumpEncoding(fout);
    1006         304 :     dumpStdStrings(fout);
    1007         304 :     dumpSearchPath(fout);
    1008             : 
    1009             :     /* The database items are always next, unless we don't want them at all */
    1010         304 :     if (dopt.outputCreateDB)
    1011         120 :         dumpDatabase(fout);
    1012             : 
    1013             :     /* Now the rearrangeable objects. */
    1014     1098608 :     for (i = 0; i < numObjs; i++)
    1015     1098304 :         dumpDumpableObject(fout, dobjs[i]);
    1016             : 
    1017             :     /*
    1018             :      * Set up options info to ensure we dump what we want.
    1019             :      */
    1020         304 :     ropt = NewRestoreOptions();
    1021         304 :     ropt->filename = filename;
    1022             : 
    1023             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1024         304 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1025         304 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1026         304 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1027         304 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1028         304 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1029         304 :     ropt->dropSchema = dopt.outputClean;
    1030         304 :     ropt->dataOnly = dopt.dataOnly;
    1031         304 :     ropt->schemaOnly = dopt.schemaOnly;
    1032         304 :     ropt->if_exists = dopt.if_exists;
    1033         304 :     ropt->column_inserts = dopt.column_inserts;
    1034         304 :     ropt->dumpSections = dopt.dumpSections;
    1035         304 :     ropt->aclsSkip = dopt.aclsSkip;
    1036         304 :     ropt->superuser = dopt.outputSuperuser;
    1037         304 :     ropt->createDB = dopt.outputCreateDB;
    1038         304 :     ropt->noOwner = dopt.outputNoOwner;
    1039         304 :     ropt->noTableAm = dopt.outputNoTableAm;
    1040         304 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1041         304 :     ropt->disable_triggers = dopt.disable_triggers;
    1042         304 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1043         304 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1044         304 :     ropt->dump_inserts = dopt.dump_inserts;
    1045         304 :     ropt->no_comments = dopt.no_comments;
    1046         304 :     ropt->no_publications = dopt.no_publications;
    1047         304 :     ropt->no_security_labels = dopt.no_security_labels;
    1048         304 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1049         304 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1050         304 :     ropt->include_everything = dopt.include_everything;
    1051         304 :     ropt->enable_row_security = dopt.enable_row_security;
    1052         304 :     ropt->sequence_data = dopt.sequence_data;
    1053         304 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1054             : 
    1055         304 :     ropt->compression_spec = compression_spec;
    1056             : 
    1057         304 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1058             : 
    1059         304 :     SetArchiveOptions(fout, &dopt, ropt);
    1060             : 
    1061             :     /* Mark which entries should be output */
    1062         304 :     ProcessArchiveRestoreOptions(fout);
    1063             : 
    1064             :     /*
    1065             :      * The archive's TOC entries are now marked as to which ones will actually
    1066             :      * be output, so we can set up their dependency lists properly. This isn't
    1067             :      * necessary for plain-text output, though.
    1068             :      */
    1069         304 :     if (!plainText)
    1070          62 :         BuildArchiveDependencies(fout);
    1071             : 
    1072             :     /*
    1073             :      * And finally we can do the actual output.
    1074             :      *
    1075             :      * Note: for non-plain-text output formats, the output file is written
    1076             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1077             :      * right now.
    1078             :      */
    1079         304 :     if (plainText)
    1080         242 :         RestoreArchive(fout);
    1081             : 
    1082         302 :     CloseArchive(fout);
    1083             : 
    1084         302 :     exit_nicely(0);
    1085             : }
    1086             : 
    1087             : 
    1088             : static void
    1089           2 : help(const char *progname)
    1090             : {
    1091           2 :     printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
    1092           2 :     printf(_("Usage:\n"));
    1093           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1094             : 
    1095           2 :     printf(_("\nGeneral options:\n"));
    1096           2 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1097           2 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1098             :              "                               plain text (default))\n"));
    1099           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1100           2 :     printf(_("  -v, --verbose                verbose mode\n"));
    1101           2 :     printf(_("  -V, --version                output version information, then exit\n"));
    1102           2 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1103             :              "                               compress as specified\n"));
    1104           2 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1105           2 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1106           2 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1107           2 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1108             : 
    1109           2 :     printf(_("\nOptions controlling the output content:\n"));
    1110           2 :     printf(_("  -a, --data-only              dump only the data, not the schema\n"));
    1111           2 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1112           2 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1113           2 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1114           2 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1115           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1116           2 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1117           2 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1118           2 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1119           2 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1120           2 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1121           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1122             :              "                               plain-text format\n"));
    1123           2 :     printf(_("  -s, --schema-only            dump only the schema, no data\n"));
    1124           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1125           2 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1126           2 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1127           2 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1128           2 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1129           2 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1130           2 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1131           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1132           2 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1133             :              "                               access to)\n"));
    1134           2 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1135           2 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1136             :              "                               do NOT dump the specified table(s), including\n"
    1137             :              "                               child and partition tables\n"));
    1138           2 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1139           2 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1140             :              "                               do NOT dump data for the specified table(s),\n"
    1141             :              "                               including child and partition tables\n"));
    1142           2 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1143           2 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1144             :              "                               based on expressions in FILENAME\n"));
    1145           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1146           2 :     printf(_("  --include-foreign-data=PATTERN\n"
    1147             :              "                               include data of foreign tables on foreign\n"
    1148             :              "                               servers matching PATTERN\n"));
    1149           2 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1150           2 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1151           2 :     printf(_("  --no-comments                do not dump comments\n"));
    1152           2 :     printf(_("  --no-publications            do not dump publications\n"));
    1153           2 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1154           2 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1155           2 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1156           2 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1157           2 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1158           2 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1159           2 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1160           2 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1161           2 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1162           2 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1163           2 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1164           2 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1165           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1166             :              "                               match at least one entity each\n"));
    1167           2 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1168             :              "                               child and partition tables\n"));
    1169           2 :     printf(_("  --use-set-session-authorization\n"
    1170             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1171             :              "                               ALTER OWNER commands to set ownership\n"));
    1172             : 
    1173           2 :     printf(_("\nConnection options:\n"));
    1174           2 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1175           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1176           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1177           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1178           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1179           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1180           2 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1181             : 
    1182           2 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1183             :              "variable value is used.\n\n"));
    1184           2 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1185           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1186           2 : }
    1187             : 
    1188             : static void
    1189         370 : setup_connection(Archive *AH, const char *dumpencoding,
    1190             :                  const char *dumpsnapshot, char *use_role)
    1191             : {
    1192         370 :     DumpOptions *dopt = AH->dopt;
    1193         370 :     PGconn     *conn = GetConnection(AH);
    1194             :     const char *std_strings;
    1195             : 
    1196         370 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1197             : 
    1198             :     /*
    1199             :      * Set the client encoding if requested.
    1200             :      */
    1201         370 :     if (dumpencoding)
    1202             :     {
    1203          36 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1204           0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1205             :                      dumpencoding);
    1206             :     }
    1207             : 
    1208             :     /*
    1209             :      * Get the active encoding and the standard_conforming_strings setting, so
    1210             :      * we know how to escape strings.
    1211             :      */
    1212         370 :     AH->encoding = PQclientEncoding(conn);
    1213             : 
    1214         370 :     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
    1215         370 :     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
    1216             : 
    1217             :     /*
    1218             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1219             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1220             :      * originally) and we should use that.
    1221             :      */
    1222         370 :     if (!use_role && AH->use_role)
    1223           4 :         use_role = AH->use_role;
    1224             : 
    1225             :     /* Set the role if requested */
    1226         370 :     if (use_role)
    1227             :     {
    1228          10 :         PQExpBuffer query = createPQExpBuffer();
    1229             : 
    1230          10 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1231          10 :         ExecuteSqlStatement(AH, query->data);
    1232          10 :         destroyPQExpBuffer(query);
    1233             : 
    1234             :         /* save it for possible later use by parallel workers */
    1235          10 :         if (!AH->use_role)
    1236           6 :             AH->use_role = pg_strdup(use_role);
    1237             :     }
    1238             : 
    1239             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1240         370 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1241             : 
    1242             :     /* Likewise, avoid using sql_standard intervalstyle */
    1243         370 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1244             : 
    1245             :     /*
    1246             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1247             :      * Otherwise, set extra_float_digits so that we can dump float data
    1248             :      * exactly (given correctly implemented float I/O code, anyway).
    1249             :      */
    1250         370 :     if (have_extra_float_digits)
    1251             :     {
    1252           0 :         PQExpBuffer q = createPQExpBuffer();
    1253             : 
    1254           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1255             :                           extra_float_digits);
    1256           0 :         ExecuteSqlStatement(AH, q->data);
    1257           0 :         destroyPQExpBuffer(q);
    1258             :     }
    1259             :     else
    1260         370 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1261             : 
    1262             :     /*
    1263             :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1264             :      * ordering across a dump and reload.
    1265             :      */
    1266         370 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1267             : 
    1268             :     /*
    1269             :      * Disable timeouts if supported.
    1270             :      */
    1271         370 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1272         370 :     if (AH->remoteVersion >= 90300)
    1273         370 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1274         370 :     if (AH->remoteVersion >= 90600)
    1275         370 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1276         370 :     if (AH->remoteVersion >= 170000)
    1277         370 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1278             : 
    1279             :     /*
    1280             :      * Quote all identifiers, if requested.
    1281             :      */
    1282         370 :     if (quote_all_identifiers)
    1283          24 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1284             : 
    1285             :     /*
    1286             :      * Adjust row-security mode, if supported.
    1287             :      */
    1288         370 :     if (AH->remoteVersion >= 90500)
    1289             :     {
    1290         370 :         if (dopt->enable_row_security)
    1291           0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1292             :         else
    1293         370 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1294             :     }
    1295             : 
    1296             :     /*
    1297             :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1298             :      * so that a parallel dump worker will have its own state.
    1299             :      */
    1300         370 :     AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
    1301             : 
    1302             :     /*
    1303             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1304             :      */
    1305         370 :     ExecuteSqlStatement(AH, "BEGIN");
    1306             : 
    1307             :     /*
    1308             :      * To support the combination of serializable_deferrable with the jobs
    1309             :      * option we use REPEATABLE READ for the worker connections that are
    1310             :      * passed a snapshot.  As long as the snapshot is acquired in a
    1311             :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1312             :      * REPEATABLE READ transaction provides the appropriate integrity
    1313             :      * guarantees.  This is a kluge, but safe for back-patching.
    1314             :      */
    1315         370 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1316           0 :         ExecuteSqlStatement(AH,
    1317             :                             "SET TRANSACTION ISOLATION LEVEL "
    1318             :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1319             :     else
    1320         370 :         ExecuteSqlStatement(AH,
    1321             :                             "SET TRANSACTION ISOLATION LEVEL "
    1322             :                             "REPEATABLE READ, READ ONLY");
    1323             : 
    1324             :     /*
    1325             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1326             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1327             :      * is already set (if the server can handle it) and we should use that.
    1328             :      */
    1329         370 :     if (dumpsnapshot)
    1330           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1331             : 
    1332         370 :     if (AH->sync_snapshot_id)
    1333             :     {
    1334          32 :         PQExpBuffer query = createPQExpBuffer();
    1335             : 
    1336          32 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1337          32 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1338          32 :         ExecuteSqlStatement(AH, query->data);
    1339          32 :         destroyPQExpBuffer(query);
    1340             :     }
    1341         338 :     else if (AH->numWorkers > 1)
    1342             :     {
    1343          16 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1344           0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1345          16 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1346             :     }
    1347         370 : }
    1348             : 
    1349             : /* Set up connection for a parallel worker process */
    1350             : static void
    1351          32 : setupDumpWorker(Archive *AH)
    1352             : {
    1353             :     /*
    1354             :      * We want to re-select all the same values the leader connection is
    1355             :      * using.  We'll have inherited directly-usable values in
    1356             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1357             :      * inherited encoding value back to a string to pass to setup_connection.
    1358             :      */
    1359          32 :     setup_connection(AH,
    1360             :                      pg_encoding_to_char(AH->encoding),
    1361             :                      NULL,
    1362             :                      NULL);
    1363          32 : }
    1364             : 
    1365             : static char *
    1366          16 : get_synchronized_snapshot(Archive *fout)
    1367             : {
    1368          16 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1369             :     char       *result;
    1370             :     PGresult   *res;
    1371             : 
    1372          16 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1373          16 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1374          16 :     PQclear(res);
    1375             : 
    1376          16 :     return result;
    1377             : }
    1378             : 
    1379             : static ArchiveFormat
    1380         356 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1381             : {
    1382             :     ArchiveFormat archiveFormat;
    1383             : 
    1384         356 :     *mode = archModeWrite;
    1385             : 
    1386         356 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1387             :     {
    1388             :         /* This is used by pg_dumpall, and is not documented */
    1389          86 :         archiveFormat = archNull;
    1390          86 :         *mode = archModeAppend;
    1391             :     }
    1392         270 :     else if (pg_strcasecmp(format, "c") == 0)
    1393           8 :         archiveFormat = archCustom;
    1394         262 :     else if (pg_strcasecmp(format, "custom") == 0)
    1395          30 :         archiveFormat = archCustom;
    1396         232 :     else if (pg_strcasecmp(format, "d") == 0)
    1397          14 :         archiveFormat = archDirectory;
    1398         218 :     else if (pg_strcasecmp(format, "directory") == 0)
    1399           6 :         archiveFormat = archDirectory;
    1400         212 :     else if (pg_strcasecmp(format, "p") == 0)
    1401         198 :         archiveFormat = archNull;
    1402          14 :     else if (pg_strcasecmp(format, "plain") == 0)
    1403           6 :         archiveFormat = archNull;
    1404           8 :     else if (pg_strcasecmp(format, "t") == 0)
    1405           4 :         archiveFormat = archTar;
    1406           4 :     else if (pg_strcasecmp(format, "tar") == 0)
    1407           2 :         archiveFormat = archTar;
    1408             :     else
    1409           2 :         pg_fatal("invalid output format \"%s\" specified", format);
    1410         354 :     return archiveFormat;
    1411             : }
    1412             : 
    1413             : /*
    1414             :  * Find the OIDs of all schemas matching the given list of patterns,
    1415             :  * and append them to the given OID list.
    1416             :  */
    1417             : static void
    1418         356 : expand_schema_name_patterns(Archive *fout,
    1419             :                             SimpleStringList *patterns,
    1420             :                             SimpleOidList *oids,
    1421             :                             bool strict_names)
    1422             : {
    1423             :     PQExpBuffer query;
    1424             :     PGresult   *res;
    1425             :     SimpleStringListCell *cell;
    1426             :     int         i;
    1427             : 
    1428         356 :     if (patterns->head == NULL)
    1429         318 :         return;                 /* nothing to do */
    1430             : 
    1431          38 :     query = createPQExpBuffer();
    1432             : 
    1433             :     /*
    1434             :      * The loop below runs multiple SELECTs might sometimes result in
    1435             :      * duplicate entries in the OID list, but we don't care.
    1436             :      */
    1437             : 
    1438          64 :     for (cell = patterns->head; cell; cell = cell->next)
    1439             :     {
    1440             :         PQExpBufferData dbbuf;
    1441             :         int         dotcnt;
    1442             : 
    1443          38 :         appendPQExpBufferStr(query,
    1444             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1445          38 :         initPQExpBuffer(&dbbuf);
    1446          38 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1447             :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1448             :                               &dotcnt);
    1449          38 :         if (dotcnt > 1)
    1450           4 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1451             :                      cell->val);
    1452          34 :         else if (dotcnt == 1)
    1453           6 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1454          28 :         termPQExpBuffer(&dbbuf);
    1455             : 
    1456          28 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1457          28 :         if (strict_names && PQntuples(res) == 0)
    1458           2 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1459             : 
    1460          50 :         for (i = 0; i < PQntuples(res); i++)
    1461             :         {
    1462          24 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1463             :         }
    1464             : 
    1465          26 :         PQclear(res);
    1466          26 :         resetPQExpBuffer(query);
    1467             :     }
    1468             : 
    1469          26 :     destroyPQExpBuffer(query);
    1470             : }
    1471             : 
    1472             : /*
    1473             :  * Find the OIDs of all extensions matching the given list of patterns,
    1474             :  * and append them to the given OID list.
    1475             :  */
    1476             : static void
    1477         316 : expand_extension_name_patterns(Archive *fout,
    1478             :                                SimpleStringList *patterns,
    1479             :                                SimpleOidList *oids,
    1480             :                                bool strict_names)
    1481             : {
    1482             :     PQExpBuffer query;
    1483             :     PGresult   *res;
    1484             :     SimpleStringListCell *cell;
    1485             :     int         i;
    1486             : 
    1487         316 :     if (patterns->head == NULL)
    1488         302 :         return;                 /* nothing to do */
    1489             : 
    1490          14 :     query = createPQExpBuffer();
    1491             : 
    1492             :     /*
    1493             :      * The loop below runs multiple SELECTs might sometimes result in
    1494             :      * duplicate entries in the OID list, but we don't care.
    1495             :      */
    1496          28 :     for (cell = patterns->head; cell; cell = cell->next)
    1497             :     {
    1498             :         int         dotcnt;
    1499             : 
    1500          14 :         appendPQExpBufferStr(query,
    1501             :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1502          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1503             :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1504             :                               &dotcnt);
    1505          14 :         if (dotcnt > 0)
    1506           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1507             :                      cell->val);
    1508             : 
    1509          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1510          14 :         if (strict_names && PQntuples(res) == 0)
    1511           0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1512             : 
    1513          26 :         for (i = 0; i < PQntuples(res); i++)
    1514             :         {
    1515          12 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1516             :         }
    1517             : 
    1518          14 :         PQclear(res);
    1519          14 :         resetPQExpBuffer(query);
    1520             :     }
    1521             : 
    1522          14 :     destroyPQExpBuffer(query);
    1523             : }
    1524             : 
    1525             : /*
    1526             :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1527             :  * and append them to the given OID list.
    1528             :  */
    1529             : static void
    1530         310 : expand_foreign_server_name_patterns(Archive *fout,
    1531             :                                     SimpleStringList *patterns,
    1532             :                                     SimpleOidList *oids)
    1533             : {
    1534             :     PQExpBuffer query;
    1535             :     PGresult   *res;
    1536             :     SimpleStringListCell *cell;
    1537             :     int         i;
    1538             : 
    1539         310 :     if (patterns->head == NULL)
    1540         304 :         return;                 /* nothing to do */
    1541             : 
    1542           6 :     query = createPQExpBuffer();
    1543             : 
    1544             :     /*
    1545             :      * The loop below runs multiple SELECTs might sometimes result in
    1546             :      * duplicate entries in the OID list, but we don't care.
    1547             :      */
    1548             : 
    1549          10 :     for (cell = patterns->head; cell; cell = cell->next)
    1550             :     {
    1551             :         int         dotcnt;
    1552             : 
    1553           6 :         appendPQExpBufferStr(query,
    1554             :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1555           6 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1556             :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1557             :                               &dotcnt);
    1558           6 :         if (dotcnt > 0)
    1559           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1560             :                      cell->val);
    1561             : 
    1562           6 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1563           6 :         if (PQntuples(res) == 0)
    1564           2 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1565             : 
    1566           8 :         for (i = 0; i < PQntuples(res); i++)
    1567           4 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1568             : 
    1569           4 :         PQclear(res);
    1570           4 :         resetPQExpBuffer(query);
    1571             :     }
    1572             : 
    1573           4 :     destroyPQExpBuffer(query);
    1574             : }
    1575             : 
    1576             : /*
    1577             :  * Find the OIDs of all tables matching the given list of patterns,
    1578             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1579             :  * in pg_dumpall.c
    1580             :  */
    1581             : static void
    1582        1878 : expand_table_name_patterns(Archive *fout,
    1583             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1584             :                            bool strict_names, bool with_child_tables)
    1585             : {
    1586             :     PQExpBuffer query;
    1587             :     PGresult   *res;
    1588             :     SimpleStringListCell *cell;
    1589             :     int         i;
    1590             : 
    1591        1878 :     if (patterns->head == NULL)
    1592        1820 :         return;                 /* nothing to do */
    1593             : 
    1594          58 :     query = createPQExpBuffer();
    1595             : 
    1596             :     /*
    1597             :      * this might sometimes result in duplicate entries in the OID list, but
    1598             :      * we don't care.
    1599             :      */
    1600             : 
    1601         118 :     for (cell = patterns->head; cell; cell = cell->next)
    1602             :     {
    1603             :         PQExpBufferData dbbuf;
    1604             :         int         dotcnt;
    1605             : 
    1606             :         /*
    1607             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1608             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1609             :          * search_path argument.
    1610             :          *
    1611             :          * For with_child_tables, we start with the basic query's results and
    1612             :          * recursively search the inheritance tree to add child tables.
    1613             :          */
    1614          70 :         if (with_child_tables)
    1615             :         {
    1616          12 :             appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1617             :         }
    1618             : 
    1619          70 :         appendPQExpBuffer(query,
    1620             :                           "SELECT c.oid"
    1621             :                           "\nFROM pg_catalog.pg_class c"
    1622             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1623             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1624             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1625             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1626             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1627             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1628             :                           RELKIND_PARTITIONED_TABLE);
    1629          70 :         initPQExpBuffer(&dbbuf);
    1630          70 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1631             :                               false, "n.nspname", "c.relname", NULL,
    1632             :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1633             :                               &dotcnt);
    1634          70 :         if (dotcnt > 2)
    1635           2 :             pg_fatal("improper relation name (too many dotted names): %s",
    1636             :                      cell->val);
    1637          68 :         else if (dotcnt == 2)
    1638           4 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1639          64 :         termPQExpBuffer(&dbbuf);
    1640             : 
    1641          64 :         if (with_child_tables)
    1642             :         {
    1643          12 :             appendPQExpBuffer(query, "UNION"
    1644             :                               "\nSELECT i.inhrelid"
    1645             :                               "\nFROM partition_tree p"
    1646             :                               "\n     JOIN pg_catalog.pg_inherits i"
    1647             :                               "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1648             :                               "\n)"
    1649             :                               "\nSELECT relid FROM partition_tree");
    1650             :         }
    1651             : 
    1652          64 :         ExecuteSqlStatement(fout, "RESET search_path");
    1653          64 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1654          64 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1655             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1656          64 :         if (strict_names && PQntuples(res) == 0)
    1657           4 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1658             : 
    1659         148 :         for (i = 0; i < PQntuples(res); i++)
    1660             :         {
    1661          88 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1662             :         }
    1663             : 
    1664          60 :         PQclear(res);
    1665          60 :         resetPQExpBuffer(query);
    1666             :     }
    1667             : 
    1668          48 :     destroyPQExpBuffer(query);
    1669             : }
    1670             : 
    1671             : /*
    1672             :  * Verifies that the connected database name matches the given database name,
    1673             :  * and if not, dies with an error about the given pattern.
    1674             :  *
    1675             :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1676             :  */
    1677             : static void
    1678          10 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1679             : {
    1680             :     const char *db;
    1681             : 
    1682          10 :     db = PQdb(conn);
    1683          10 :     if (db == NULL)
    1684           0 :         pg_fatal("You are currently not connected to a database.");
    1685             : 
    1686          10 :     if (strcmp(db, dbname) != 0)
    1687          10 :         pg_fatal("cross-database references are not implemented: %s",
    1688             :                  pattern);
    1689           0 : }
    1690             : 
    1691             : /*
    1692             :  * checkExtensionMembership
    1693             :  *      Determine whether object is an extension member, and if so,
    1694             :  *      record an appropriate dependency and set the object's dump flag.
    1695             :  *
    1696             :  * It's important to call this for each object that could be an extension
    1697             :  * member.  Generally, we integrate this with determining the object's
    1698             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1699             :  *
    1700             :  * Returns true if object is an extension member, else false.
    1701             :  */
    1702             : static bool
    1703      939394 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1704             : {
    1705      939394 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1706             : 
    1707      939394 :     if (ext == NULL)
    1708      938006 :         return false;
    1709             : 
    1710        1388 :     dobj->ext_member = true;
    1711             : 
    1712             :     /* Record dependency so that getDependencies needn't deal with that */
    1713        1388 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1714             : 
    1715             :     /*
    1716             :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1717             :      * dumped.  (Any initial ACLs will be removed later, using data from
    1718             :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1719             :      * initial setup.)
    1720             :      *
    1721             :      * Prior to 9.6, we do not include any extension member components.
    1722             :      *
    1723             :      * In binary upgrades, we still dump all components of the members
    1724             :      * individually, since the idea is to exactly reproduce the database
    1725             :      * contents rather than replace the extension contents with something
    1726             :      * different.
    1727             :      *
    1728             :      * Note: it might be interesting someday to implement storage and delta
    1729             :      * dumping of extension members' RLS policies and/or security labels.
    1730             :      * However there is a pitfall for RLS policies: trying to dump them
    1731             :      * requires getting a lock on their tables, and the calling user might not
    1732             :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1733             :      * so the current feature doesn't have a problem of that sort.
    1734             :      */
    1735        1388 :     if (fout->dopt->binary_upgrade)
    1736         152 :         dobj->dump = ext->dobj.dump;
    1737             :     else
    1738             :     {
    1739        1236 :         if (fout->remoteVersion < 90600)
    1740           0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1741             :         else
    1742        1236 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1743             :     }
    1744             : 
    1745        1388 :     return true;
    1746             : }
    1747             : 
    1748             : /*
    1749             :  * selectDumpableNamespace: policy-setting subroutine
    1750             :  *      Mark a namespace as to be dumped or not
    1751             :  */
    1752             : static void
    1753        2276 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1754             : {
    1755             :     /*
    1756             :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1757             :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1758             :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1759             :      */
    1760        2276 :     nsinfo->create = true;
    1761             : 
    1762             :     /*
    1763             :      * If specific tables are being dumped, do not dump any complete
    1764             :      * namespaces. If specific namespaces are being dumped, dump just those
    1765             :      * namespaces. Otherwise, dump all non-system namespaces.
    1766             :      */
    1767        2276 :     if (table_include_oids.head != NULL)
    1768         100 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1769        2176 :     else if (schema_include_oids.head != NULL)
    1770          98 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1771          98 :             simple_oid_list_member(&schema_include_oids,
    1772             :                                    nsinfo->dobj.catId.oid) ?
    1773          98 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1774        2078 :     else if (fout->remoteVersion >= 90600 &&
    1775        2078 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1776             :     {
    1777             :         /*
    1778             :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    1779             :          * they are interesting (and not the original ACLs which were set at
    1780             :          * initdb time, see pg_init_privs).
    1781             :          */
    1782         266 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1783             :     }
    1784        1812 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1785         810 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    1786             :     {
    1787             :         /* Other system schemas don't get dumped */
    1788        1268 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1789             :     }
    1790         544 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    1791             :     {
    1792             :         /*
    1793             :          * The public schema is a strange beast that sits in a sort of
    1794             :          * no-mans-land between being a system object and a user object.
    1795             :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    1796             :          * a comment and an indication of ownership.  If the owner is the
    1797             :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    1798             :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    1799             :          */
    1800         258 :         nsinfo->create = false;
    1801         258 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1802         258 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    1803         178 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    1804         258 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    1805             : 
    1806             :         /*
    1807             :          * Also, make like it has a comment even if it doesn't; this is so
    1808             :          * that we'll emit a command to drop the comment, if appropriate.
    1809             :          * (Without this, we'd not call dumpCommentExtended for it.)
    1810             :          */
    1811         258 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    1812             :     }
    1813             :     else
    1814         286 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1815             : 
    1816             :     /*
    1817             :      * In any case, a namespace can be excluded by an exclusion switch
    1818             :      */
    1819        3104 :     if (nsinfo->dobj.dump_contains &&
    1820         828 :         simple_oid_list_member(&schema_exclude_oids,
    1821             :                                nsinfo->dobj.catId.oid))
    1822           6 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1823             : 
    1824             :     /*
    1825             :      * If the schema belongs to an extension, allow extension membership to
    1826             :      * override the dump decision for the schema itself.  However, this does
    1827             :      * not change dump_contains, so this won't change what we do with objects
    1828             :      * within the schema.  (If they belong to the extension, they'll get
    1829             :      * suppressed by it, otherwise not.)
    1830             :      */
    1831        2276 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    1832        2276 : }
    1833             : 
    1834             : /*
    1835             :  * selectDumpableTable: policy-setting subroutine
    1836             :  *      Mark a table as to be dumped or not
    1837             :  */
    1838             : static void
    1839       77126 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    1840             : {
    1841       77126 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    1842         450 :         return;                 /* extension membership overrides all else */
    1843             : 
    1844             :     /*
    1845             :      * If specific tables are being dumped, dump just those tables; else, dump
    1846             :      * according to the parent namespace's dump flag.
    1847             :      */
    1848       76676 :     if (table_include_oids.head != NULL)
    1849       10104 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    1850             :                                                    tbinfo->dobj.catId.oid) ?
    1851        5052 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1852             :     else
    1853       71624 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    1854             : 
    1855             :     /*
    1856             :      * In any case, a table can be excluded by an exclusion switch
    1857             :      */
    1858      126066 :     if (tbinfo->dobj.dump &&
    1859       49390 :         simple_oid_list_member(&table_exclude_oids,
    1860             :                                tbinfo->dobj.catId.oid))
    1861          24 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1862             : }
    1863             : 
    1864             : /*
    1865             :  * selectDumpableType: policy-setting subroutine
    1866             :  *      Mark a type as to be dumped or not
    1867             :  *
    1868             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    1869             :  * special type code to facilitate sorting into the desired order.  (We don't
    1870             :  * want to consider those to be ordinary types because that would bring tables
    1871             :  * up into the datatype part of the dump order.)  We still set the object's
    1872             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    1873             :  * need it so that casts involving such types will be dumped correctly -- see
    1874             :  * dumpCast.  This means the flag should be set the same as for the underlying
    1875             :  * object (the table or base type).
    1876             :  */
    1877             : static void
    1878      213196 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    1879             : {
    1880             :     /* skip complex types, except for standalone composite types */
    1881      213196 :     if (OidIsValid(tyinfo->typrelid) &&
    1882       75924 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    1883             :     {
    1884       75628 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    1885             : 
    1886       75628 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    1887       75628 :         if (tytable != NULL)
    1888       75628 :             tyinfo->dobj.dump = tytable->dobj.dump;
    1889             :         else
    1890           0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1891       75628 :         return;
    1892             :     }
    1893             : 
    1894             :     /* skip auto-generated array and multirange types */
    1895      137568 :     if (tyinfo->isArray || tyinfo->isMultirange)
    1896             :     {
    1897      104178 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    1898             : 
    1899             :         /*
    1900             :          * Fall through to set the dump flag; we assume that the subsequent
    1901             :          * rules will do the same thing as they would for the array's base
    1902             :          * type or multirange's range type.  (We cannot reliably look up the
    1903             :          * base type here, since getTypes may not have processed it yet.)
    1904             :          */
    1905             :     }
    1906             : 
    1907      137568 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    1908         300 :         return;                 /* extension membership overrides all else */
    1909             : 
    1910             :     /* Dump based on if the contents of the namespace are being dumped */
    1911      137268 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    1912             : }
    1913             : 
    1914             : /*
    1915             :  * selectDumpableDefaultACL: policy-setting subroutine
    1916             :  *      Mark a default ACL as to be dumped or not
    1917             :  *
    1918             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    1919             :  * Otherwise dump if we are dumping "everything".  Note that dataOnly
    1920             :  * and aclsSkip are checked separately.
    1921             :  */
    1922             : static void
    1923         344 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    1924             : {
    1925             :     /* Default ACLs can't be extension members */
    1926             : 
    1927         344 :     if (dinfo->dobj.namespace)
    1928             :         /* default ACLs are considered part of the namespace */
    1929         172 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    1930             :     else
    1931         172 :         dinfo->dobj.dump = dopt->include_everything ?
    1932         172 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1933         344 : }
    1934             : 
    1935             : /*
    1936             :  * selectDumpableCast: policy-setting subroutine
    1937             :  *      Mark a cast as to be dumped or not
    1938             :  *
    1939             :  * Casts do not belong to any particular namespace (since they haven't got
    1940             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    1941             :  * casts from built-in ones, we must resort to checking whether the cast's
    1942             :  * OID is in the range reserved for initdb.
    1943             :  */
    1944             : static void
    1945       67938 : selectDumpableCast(CastInfo *cast, Archive *fout)
    1946             : {
    1947       67938 :     if (checkExtensionMembership(&cast->dobj, fout))
    1948           0 :         return;                 /* extension membership overrides all else */
    1949             : 
    1950             :     /*
    1951             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    1952             :      * support ACLs currently.
    1953             :      */
    1954       67938 :     if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    1955       67792 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    1956             :     else
    1957         146 :         cast->dobj.dump = fout->dopt->include_everything ?
    1958         146 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1959             : }
    1960             : 
    1961             : /*
    1962             :  * selectDumpableProcLang: policy-setting subroutine
    1963             :  *      Mark a procedural language as to be dumped or not
    1964             :  *
    1965             :  * Procedural languages do not belong to any particular namespace.  To
    1966             :  * identify built-in languages, we must resort to checking whether the
    1967             :  * language's OID is in the range reserved for initdb.
    1968             :  */
    1969             : static void
    1970         390 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    1971             : {
    1972         390 :     if (checkExtensionMembership(&plang->dobj, fout))
    1973         304 :         return;                 /* extension membership overrides all else */
    1974             : 
    1975             :     /*
    1976             :      * Only include procedural languages when we are dumping everything.
    1977             :      *
    1978             :      * For from-initdb procedural languages, only include ACLs, as we do for
    1979             :      * the pg_catalog namespace.  We need this because procedural languages do
    1980             :      * not live in any namespace.
    1981             :      */
    1982          86 :     if (!fout->dopt->include_everything)
    1983          16 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    1984             :     else
    1985             :     {
    1986          70 :         if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    1987           0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    1988           0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    1989             :         else
    1990          70 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    1991             :     }
    1992             : }
    1993             : 
    1994             : /*
    1995             :  * selectDumpableAccessMethod: policy-setting subroutine
    1996             :  *      Mark an access method as to be dumped or not
    1997             :  *
    1998             :  * Access methods do not belong to any particular namespace.  To identify
    1999             :  * built-in access methods, we must resort to checking whether the
    2000             :  * method's OID is in the range reserved for initdb.
    2001             :  */
    2002             : static void
    2003        2360 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2004             : {
    2005        2360 :     if (checkExtensionMembership(&method->dobj, fout))
    2006          50 :         return;                 /* extension membership overrides all else */
    2007             : 
    2008             :     /*
    2009             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2010             :      * they do not support ACLs currently.
    2011             :      */
    2012        2310 :     if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2013        2128 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2014             :     else
    2015         182 :         method->dobj.dump = fout->dopt->include_everything ?
    2016         182 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2017             : }
    2018             : 
    2019             : /*
    2020             :  * selectDumpableExtension: policy-setting subroutine
    2021             :  *      Mark an extension as to be dumped or not
    2022             :  *
    2023             :  * Built-in extensions should be skipped except for checking ACLs, since we
    2024             :  * assume those will already be installed in the target database.  We identify
    2025             :  * such extensions by their having OIDs in the range reserved for initdb.
    2026             :  * We dump all user-added extensions by default.  No extensions are dumped
    2027             :  * if include_everything is false (i.e., a --schema or --table switch was
    2028             :  * given), except if --extension specifies a list of extensions to dump.
    2029             :  */
    2030             : static void
    2031         356 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2032             : {
    2033             :     /*
    2034             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2035             :      * change permissions on their member objects, if they wish to, and have
    2036             :      * those changes preserved.
    2037             :      */
    2038         356 :     if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2039         306 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2040             :     else
    2041             :     {
    2042             :         /* check if there is a list of extensions to dump */
    2043          50 :         if (extension_include_oids.head != NULL)
    2044           8 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2045           8 :                 simple_oid_list_member(&extension_include_oids,
    2046             :                                        extinfo->dobj.catId.oid) ?
    2047           8 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2048             :         else
    2049          42 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2050          42 :                 dopt->include_everything ?
    2051          42 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2052             : 
    2053             :         /* check that the extension is not explicitly excluded */
    2054          92 :         if (extinfo->dobj.dump &&
    2055          42 :             simple_oid_list_member(&extension_exclude_oids,
    2056             :                                    extinfo->dobj.catId.oid))
    2057           4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2058             :     }
    2059         356 : }
    2060             : 
    2061             : /*
    2062             :  * selectDumpablePublicationObject: policy-setting subroutine
    2063             :  *      Mark a publication object as to be dumped or not
    2064             :  *
    2065             :  * A publication can have schemas and tables which have schemas, but those are
    2066             :  * ignored in decision making, because publications are only dumped when we are
    2067             :  * dumping everything.
    2068             :  */
    2069             : static void
    2070         652 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2071             : {
    2072         652 :     if (checkExtensionMembership(dobj, fout))
    2073           0 :         return;                 /* extension membership overrides all else */
    2074             : 
    2075         652 :     dobj->dump = fout->dopt->include_everything ?
    2076         652 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2077             : }
    2078             : 
    2079             : /*
    2080             :  * selectDumpableStatisticsObject: policy-setting subroutine
    2081             :  *      Mark an extended statistics object as to be dumped or not
    2082             :  *
    2083             :  * We dump an extended statistics object if the schema it's in and the table
    2084             :  * it's for are being dumped.  (This'll need more thought if statistics
    2085             :  * objects ever support cross-table stats.)
    2086             :  */
    2087             : static void
    2088         298 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2089             : {
    2090         298 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2091           0 :         return;                 /* extension membership overrides all else */
    2092             : 
    2093         298 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2094         298 :     if (sobj->stattable == NULL ||
    2095         298 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2096          40 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2097             : }
    2098             : 
    2099             : /*
    2100             :  * selectDumpableObject: policy-setting subroutine
    2101             :  *      Mark a generic dumpable object as to be dumped or not
    2102             :  *
    2103             :  * Use this only for object types without a special-case routine above.
    2104             :  */
    2105             : static void
    2106      650786 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2107             : {
    2108      650786 :     if (checkExtensionMembership(dobj, fout))
    2109         234 :         return;                 /* extension membership overrides all else */
    2110             : 
    2111             :     /*
    2112             :      * Default policy is to dump if parent namespace is dumpable, or for
    2113             :      * non-namespace-associated items, dump if we're dumping "everything".
    2114             :      */
    2115      650552 :     if (dobj->namespace)
    2116      649484 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2117             :     else
    2118        1068 :         dobj->dump = fout->dopt->include_everything ?
    2119        1068 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2120             : }
    2121             : 
    2122             : /*
    2123             :  *  Dump a table's contents for loading using the COPY command
    2124             :  *  - this routine is called by the Archiver when it wants the table
    2125             :  *    to be dumped.
    2126             :  */
    2127             : static int
    2128        6750 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2129             : {
    2130        6750 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2131        6750 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2132        6750 :     const char *classname = tbinfo->dobj.name;
    2133        6750 :     PQExpBuffer q = createPQExpBuffer();
    2134             : 
    2135             :     /*
    2136             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2137             :      * which uses it already.
    2138             :      */
    2139        6750 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2140        6750 :     PGconn     *conn = GetConnection(fout);
    2141             :     PGresult   *res;
    2142             :     int         ret;
    2143             :     char       *copybuf;
    2144             :     const char *column_list;
    2145             : 
    2146        6750 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2147             :                 tbinfo->dobj.namespace->dobj.name, classname);
    2148             : 
    2149             :     /*
    2150             :      * Specify the column list explicitly so that we have no possibility of
    2151             :      * retrieving data in the wrong column order.  (The default column
    2152             :      * ordering of COPY will not be what we want in certain corner cases
    2153             :      * involving ADD COLUMN and inheritance.)
    2154             :      */
    2155        6750 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2156             : 
    2157             :     /*
    2158             :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
    2159             :      * a filter condition was specified.  For other cases a simple COPY
    2160             :      * suffices.
    2161             :      */
    2162        6750 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2163             :     {
    2164           2 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2165             :         /* klugery to get rid of parens in column list */
    2166           2 :         if (strlen(column_list) > 2)
    2167             :         {
    2168           2 :             appendPQExpBufferStr(q, column_list + 1);
    2169           2 :             q->data[q->len - 1] = ' ';
    2170             :         }
    2171             :         else
    2172           0 :             appendPQExpBufferStr(q, "* ");
    2173             : 
    2174           4 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2175           2 :                           fmtQualifiedDumpable(tbinfo),
    2176           2 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2177             :     }
    2178             :     else
    2179             :     {
    2180        6748 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2181        6748 :                           fmtQualifiedDumpable(tbinfo),
    2182             :                           column_list);
    2183             :     }
    2184        6750 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2185        6748 :     PQclear(res);
    2186        6748 :     destroyPQExpBuffer(clistBuf);
    2187             : 
    2188             :     for (;;)
    2189             :     {
    2190     3425918 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2191             : 
    2192     3425918 :         if (ret < 0)
    2193        6748 :             break;              /* done or error */
    2194             : 
    2195     3419170 :         if (copybuf)
    2196             :         {
    2197     3419170 :             WriteData(fout, copybuf, ret);
    2198     3419170 :             PQfreemem(copybuf);
    2199             :         }
    2200             : 
    2201             :         /* ----------
    2202             :          * THROTTLE:
    2203             :          *
    2204             :          * There was considerable discussion in late July, 2000 regarding
    2205             :          * slowing down pg_dump when backing up large tables. Users with both
    2206             :          * slow & fast (multi-processor) machines experienced performance
    2207             :          * degradation when doing a backup.
    2208             :          *
    2209             :          * Initial attempts based on sleeping for a number of ms for each ms
    2210             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2211             :          * implementation was suggested. The latter failed because the loop
    2212             :          * was too tight. Finally, the following was implemented:
    2213             :          *
    2214             :          * If throttle is non-zero, then
    2215             :          *      See how long since the last sleep.
    2216             :          *      Work out how long to sleep (based on ratio).
    2217             :          *      If sleep is more than 100ms, then
    2218             :          *          sleep
    2219             :          *          reset timer
    2220             :          *      EndIf
    2221             :          * EndIf
    2222             :          *
    2223             :          * where the throttle value was the number of ms to sleep per ms of
    2224             :          * work. The calculation was done in each loop.
    2225             :          *
    2226             :          * Most of the hard work is done in the backend, and this solution
    2227             :          * still did not work particularly well: on slow machines, the ratio
    2228             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2229             :          * multi-processor machines, it had little or no effect, for reasons
    2230             :          * that were unclear.
    2231             :          *
    2232             :          * Further discussion ensued, and the proposal was dropped.
    2233             :          *
    2234             :          * For those people who want this feature, it can be implemented using
    2235             :          * gettimeofday in each loop, calculating the time since last sleep,
    2236             :          * multiplying that by the sleep ratio, then if the result is more
    2237             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2238             :          * function to sleep for a subsecond period ie.
    2239             :          *
    2240             :          * select(0, NULL, NULL, NULL, &tvi);
    2241             :          *
    2242             :          * This will return after the interval specified in the structure tvi.
    2243             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2244             :          * ----------
    2245             :          */
    2246             :     }
    2247        6748 :     archprintf(fout, "\\.\n\n\n");
    2248             : 
    2249        6748 :     if (ret == -2)
    2250             :     {
    2251             :         /* copy data transfer failed */
    2252           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2253           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2254           0 :         pg_log_error_detail("Command was: %s", q->data);
    2255           0 :         exit_nicely(1);
    2256             :     }
    2257             : 
    2258             :     /* Check command status and return to normal libpq state */
    2259        6748 :     res = PQgetResult(conn);
    2260        6748 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2261             :     {
    2262           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2263           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2264           0 :         pg_log_error_detail("Command was: %s", q->data);
    2265           0 :         exit_nicely(1);
    2266             :     }
    2267        6748 :     PQclear(res);
    2268             : 
    2269             :     /* Do this to ensure we've pumped libpq back to idle state */
    2270        6748 :     if (PQgetResult(conn) != NULL)
    2271           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2272             :                        classname);
    2273             : 
    2274        6748 :     destroyPQExpBuffer(q);
    2275        6748 :     return 1;
    2276             : }
    2277             : 
    2278             : /*
    2279             :  * Dump table data using INSERT commands.
    2280             :  *
    2281             :  * Caution: when we restore from an archive file direct to database, the
    2282             :  * INSERT commands emitted by this function have to be parsed by
    2283             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2284             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2285             :  */
    2286             : static int
    2287         138 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2288             : {
    2289         138 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2290         138 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2291         138 :     DumpOptions *dopt = fout->dopt;
    2292         138 :     PQExpBuffer q = createPQExpBuffer();
    2293         138 :     PQExpBuffer insertStmt = NULL;
    2294             :     char       *attgenerated;
    2295             :     PGresult   *res;
    2296             :     int         nfields,
    2297             :                 i;
    2298         138 :     int         rows_per_statement = dopt->dump_inserts;
    2299         138 :     int         rows_this_statement = 0;
    2300             : 
    2301             :     /*
    2302             :      * If we're going to emit INSERTs with column names, the most efficient
    2303             :      * way to deal with generated columns is to exclude them entirely.  For
    2304             :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2305             :      * actual column value --- but we can save a few cycles by fetching nulls
    2306             :      * rather than the uninteresting-to-us value.
    2307             :      */
    2308         138 :     attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
    2309         138 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2310         138 :     nfields = 0;
    2311         442 :     for (i = 0; i < tbinfo->numatts; i++)
    2312             :     {
    2313         304 :         if (tbinfo->attisdropped[i])
    2314           4 :             continue;
    2315         300 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2316          10 :             continue;
    2317         290 :         if (nfields > 0)
    2318         166 :             appendPQExpBufferStr(q, ", ");
    2319         290 :         if (tbinfo->attgenerated[i])
    2320          10 :             appendPQExpBufferStr(q, "NULL");
    2321             :         else
    2322         280 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2323         290 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2324         290 :         nfields++;
    2325             :     }
    2326             :     /* Servers before 9.4 will complain about zero-column SELECT */
    2327         138 :     if (nfields == 0)
    2328          14 :         appendPQExpBufferStr(q, "NULL");
    2329         138 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2330         138 :                       fmtQualifiedDumpable(tbinfo));
    2331         138 :     if (tdinfo->filtercond)
    2332           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2333             : 
    2334         138 :     ExecuteSqlStatement(fout, q->data);
    2335             : 
    2336             :     while (1)
    2337             :     {
    2338         238 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2339             :                               PGRES_TUPLES_OK);
    2340             : 
    2341             :         /* cross-check field count, allowing for dummy NULL if any */
    2342         238 :         if (nfields != PQnfields(res) &&
    2343          20 :             !(nfields == 0 && PQnfields(res) == 1))
    2344           0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2345             :                      tbinfo->dobj.name);
    2346             : 
    2347             :         /*
    2348             :          * First time through, we build as much of the INSERT statement as
    2349             :          * possible in "insertStmt", which we can then just print for each
    2350             :          * statement. If the table happens to have zero dumpable columns then
    2351             :          * this will be a complete statement, otherwise it will end in
    2352             :          * "VALUES" and be ready to have the row's column values printed.
    2353             :          */
    2354         238 :         if (insertStmt == NULL)
    2355             :         {
    2356             :             TableInfo  *targettab;
    2357             : 
    2358         138 :             insertStmt = createPQExpBuffer();
    2359             : 
    2360             :             /*
    2361             :              * When load-via-partition-root is set or forced, get the root
    2362             :              * table name for the partition table, so that we can reload data
    2363             :              * through the root table.
    2364             :              */
    2365         138 :             if (tbinfo->ispartition &&
    2366          80 :                 (dopt->load_via_partition_root ||
    2367          40 :                  forcePartitionRootLoad(tbinfo)))
    2368           6 :                 targettab = getRootTableInfo(tbinfo);
    2369             :             else
    2370         132 :                 targettab = tbinfo;
    2371             : 
    2372         138 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2373         138 :                               fmtQualifiedDumpable(targettab));
    2374             : 
    2375             :             /* corner case for zero-column table */
    2376         138 :             if (nfields == 0)
    2377             :             {
    2378          14 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2379             :             }
    2380             :             else
    2381             :             {
    2382             :                 /* append the list of column names if required */
    2383         124 :                 if (dopt->column_inserts)
    2384             :                 {
    2385          54 :                     appendPQExpBufferChar(insertStmt, '(');
    2386         176 :                     for (int field = 0; field < nfields; field++)
    2387             :                     {
    2388         122 :                         if (field > 0)
    2389          68 :                             appendPQExpBufferStr(insertStmt, ", ");
    2390         122 :                         appendPQExpBufferStr(insertStmt,
    2391         122 :                                              fmtId(PQfname(res, field)));
    2392             :                     }
    2393          54 :                     appendPQExpBufferStr(insertStmt, ") ");
    2394             :                 }
    2395             : 
    2396         124 :                 if (tbinfo->needs_override)
    2397           4 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2398             : 
    2399         124 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2400             :             }
    2401             :         }
    2402             : 
    2403        6380 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2404             :         {
    2405             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2406        6142 :             if (rows_this_statement == 0)
    2407        6130 :                 archputs(insertStmt->data, fout);
    2408             : 
    2409             :             /*
    2410             :              * If it is zero-column table then we've already written the
    2411             :              * complete statement, which will mean we've disobeyed
    2412             :              * --rows-per-insert when it's set greater than 1.  We do support
    2413             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2414             :              * UNION ALL ... but that's non-standard so we should avoid it
    2415             :              * given that using INSERTs is mostly only ever needed for
    2416             :              * cross-database exports.
    2417             :              */
    2418        6142 :             if (nfields == 0)
    2419          12 :                 continue;
    2420             : 
    2421             :             /* Emit a row heading */
    2422        6130 :             if (rows_per_statement == 1)
    2423        6112 :                 archputs(" (", fout);
    2424          18 :             else if (rows_this_statement > 0)
    2425          12 :                 archputs(",\n\t(", fout);
    2426             :             else
    2427           6 :                 archputs("\n\t(", fout);
    2428             : 
    2429       18498 :             for (int field = 0; field < nfields; field++)
    2430             :             {
    2431       12368 :                 if (field > 0)
    2432        6238 :                     archputs(", ", fout);
    2433       12368 :                 if (attgenerated[field])
    2434             :                 {
    2435           4 :                     archputs("DEFAULT", fout);
    2436           4 :                     continue;
    2437             :                 }
    2438       12364 :                 if (PQgetisnull(res, tuple, field))
    2439             :                 {
    2440         166 :                     archputs("NULL", fout);
    2441         166 :                     continue;
    2442             :                 }
    2443             : 
    2444             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2445       12198 :                 switch (PQftype(res, field))
    2446             :                 {
    2447        8138 :                     case INT2OID:
    2448             :                     case INT4OID:
    2449             :                     case INT8OID:
    2450             :                     case OIDOID:
    2451             :                     case FLOAT4OID:
    2452             :                     case FLOAT8OID:
    2453             :                     case NUMERICOID:
    2454             :                         {
    2455             :                             /*
    2456             :                              * These types are printed without quotes unless
    2457             :                              * they contain values that aren't accepted by the
    2458             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2459             :                              * strtod() and friends might accept NaN, so we
    2460             :                              * can't use that to test.
    2461             :                              *
    2462             :                              * In reality we only need to defend against
    2463             :                              * infinity and NaN, so we need not get too crazy
    2464             :                              * about pattern matching here.
    2465             :                              */
    2466        8138 :                             const char *s = PQgetvalue(res, tuple, field);
    2467             : 
    2468        8138 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2469        8134 :                                 archputs(s, fout);
    2470             :                             else
    2471           4 :                                 archprintf(fout, "'%s'", s);
    2472             :                         }
    2473        8138 :                         break;
    2474             : 
    2475           4 :                     case BITOID:
    2476             :                     case VARBITOID:
    2477           4 :                         archprintf(fout, "B'%s'",
    2478             :                                    PQgetvalue(res, tuple, field));
    2479           4 :                         break;
    2480             : 
    2481           8 :                     case BOOLOID:
    2482           8 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2483           4 :                             archputs("true", fout);
    2484             :                         else
    2485           4 :                             archputs("false", fout);
    2486           8 :                         break;
    2487             : 
    2488        4048 :                     default:
    2489             :                         /* All other types are printed as string literals. */
    2490        4048 :                         resetPQExpBuffer(q);
    2491        4048 :                         appendStringLiteralAH(q,
    2492             :                                               PQgetvalue(res, tuple, field),
    2493             :                                               fout);
    2494        4048 :                         archputs(q->data, fout);
    2495        4048 :                         break;
    2496             :                 }
    2497             :             }
    2498             : 
    2499             :             /* Terminate the row ... */
    2500        6130 :             archputs(")", fout);
    2501             : 
    2502             :             /* ... and the statement, if the target no. of rows is reached */
    2503        6130 :             if (++rows_this_statement >= rows_per_statement)
    2504             :             {
    2505        6116 :                 if (dopt->do_nothing)
    2506           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2507             :                 else
    2508        6116 :                     archputs(";\n", fout);
    2509             :                 /* Reset the row counter */
    2510        6116 :                 rows_this_statement = 0;
    2511             :             }
    2512             :         }
    2513             : 
    2514         238 :         if (PQntuples(res) <= 0)
    2515             :         {
    2516         138 :             PQclear(res);
    2517         138 :             break;
    2518             :         }
    2519         100 :         PQclear(res);
    2520             :     }
    2521             : 
    2522             :     /* Terminate any statements that didn't make the row count. */
    2523         138 :     if (rows_this_statement > 0)
    2524             :     {
    2525           2 :         if (dopt->do_nothing)
    2526           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2527             :         else
    2528           2 :             archputs(";\n", fout);
    2529             :     }
    2530             : 
    2531         138 :     archputs("\n\n", fout);
    2532             : 
    2533         138 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2534             : 
    2535         138 :     destroyPQExpBuffer(q);
    2536         138 :     if (insertStmt != NULL)
    2537         138 :         destroyPQExpBuffer(insertStmt);
    2538         138 :     free(attgenerated);
    2539             : 
    2540         138 :     return 1;
    2541             : }
    2542             : 
    2543             : /*
    2544             :  * getRootTableInfo:
    2545             :  *     get the root TableInfo for the given partition table.
    2546             :  */
    2547             : static TableInfo *
    2548          18 : getRootTableInfo(const TableInfo *tbinfo)
    2549             : {
    2550             :     TableInfo  *parentTbinfo;
    2551             : 
    2552             :     Assert(tbinfo->ispartition);
    2553             :     Assert(tbinfo->numParents == 1);
    2554             : 
    2555          18 :     parentTbinfo = tbinfo->parents[0];
    2556          18 :     while (parentTbinfo->ispartition)
    2557             :     {
    2558             :         Assert(parentTbinfo->numParents == 1);
    2559           0 :         parentTbinfo = parentTbinfo->parents[0];
    2560             :     }
    2561             : 
    2562          18 :     return parentTbinfo;
    2563             : }
    2564             : 
    2565             : /*
    2566             :  * forcePartitionRootLoad
    2567             :  *     Check if we must force load_via_partition_root for this partition.
    2568             :  *
    2569             :  * This is required if any level of ancestral partitioned table has an
    2570             :  * unsafe partitioning scheme.
    2571             :  */
    2572             : static bool
    2573        1868 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2574             : {
    2575             :     TableInfo  *parentTbinfo;
    2576             : 
    2577             :     Assert(tbinfo->ispartition);
    2578             :     Assert(tbinfo->numParents == 1);
    2579             : 
    2580        1868 :     parentTbinfo = tbinfo->parents[0];
    2581        1868 :     if (parentTbinfo->unsafe_partitions)
    2582          18 :         return true;
    2583        2282 :     while (parentTbinfo->ispartition)
    2584             :     {
    2585             :         Assert(parentTbinfo->numParents == 1);
    2586         432 :         parentTbinfo = parentTbinfo->parents[0];
    2587         432 :         if (parentTbinfo->unsafe_partitions)
    2588           0 :             return true;
    2589             :     }
    2590             : 
    2591        1850 :     return false;
    2592             : }
    2593             : 
    2594             : /*
    2595             :  * dumpTableData -
    2596             :  *    dump the contents of a single table
    2597             :  *
    2598             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2599             :  */
    2600             : static void
    2601        7024 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2602             : {
    2603        7024 :     DumpOptions *dopt = fout->dopt;
    2604        7024 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2605        7024 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2606        7024 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2607             :     DataDumperPtr dumpFn;
    2608        7024 :     char       *tdDefn = NULL;
    2609             :     char       *copyStmt;
    2610             :     const char *copyFrom;
    2611             : 
    2612             :     /* We had better have loaded per-column details about this table */
    2613             :     Assert(tbinfo->interesting);
    2614             : 
    2615             :     /*
    2616             :      * When load-via-partition-root is set or forced, get the root table name
    2617             :      * for the partition table, so that we can reload data through the root
    2618             :      * table.  Then construct a comment to be inserted into the TOC entry's
    2619             :      * defn field, so that such cases can be identified reliably.
    2620             :      */
    2621        7024 :     if (tbinfo->ispartition &&
    2622        3656 :         (dopt->load_via_partition_root ||
    2623        1828 :          forcePartitionRootLoad(tbinfo)))
    2624          12 :     {
    2625             :         TableInfo  *parentTbinfo;
    2626             : 
    2627          12 :         parentTbinfo = getRootTableInfo(tbinfo);
    2628          12 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2629          12 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2630             :                           copyFrom);
    2631          12 :         tdDefn = pg_strdup(copyBuf->data);
    2632             :     }
    2633             :     else
    2634        7012 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2635             : 
    2636        7024 :     if (dopt->dump_inserts == 0)
    2637             :     {
    2638             :         /* Dump/restore using COPY */
    2639        6886 :         dumpFn = dumpTableData_copy;
    2640             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2641        6886 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2642             :                           copyFrom);
    2643        6886 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2644             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2645        6886 :         copyStmt = copyBuf->data;
    2646             :     }
    2647             :     else
    2648             :     {
    2649             :         /* Restore using INSERT */
    2650         138 :         dumpFn = dumpTableData_insert;
    2651         138 :         copyStmt = NULL;
    2652             :     }
    2653             : 
    2654             :     /*
    2655             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2656             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2657             :      * See comments for BuildArchiveDependencies.
    2658             :      */
    2659        7024 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2660             :     {
    2661             :         TocEntry   *te;
    2662             : 
    2663        7024 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2664        7024 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2665             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2666             :                                        .owner = tbinfo->rolname,
    2667             :                                        .description = "TABLE DATA",
    2668             :                                        .section = SECTION_DATA,
    2669             :                                        .createStmt = tdDefn,
    2670             :                                        .copyStmt = copyStmt,
    2671             :                                        .deps = &(tbinfo->dobj.dumpId),
    2672             :                                        .nDeps = 1,
    2673             :                                        .dumpFn = dumpFn,
    2674             :                                        .dumpArg = tdinfo));
    2675             : 
    2676             :         /*
    2677             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2678             :          * and want to order dump jobs by table size.  We choose to measure
    2679             :          * dataLength in table pages (including TOAST pages) during dump, so
    2680             :          * no scaling is needed.
    2681             :          *
    2682             :          * However, relpages is declared as "integer" in pg_class, and hence
    2683             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2684             :          * Cast so that we get the right interpretation of table sizes
    2685             :          * exceeding INT_MAX pages.
    2686             :          */
    2687        7024 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2688        7024 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2689             : 
    2690             :         /*
    2691             :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2692             :          * and instead we'd better worry about integer overflow.  Clamp to
    2693             :          * INT_MAX if the correct result exceeds that.
    2694             :          */
    2695             :         if (sizeof(te->dataLength) == 4 &&
    2696             :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2697             :              te->dataLength < 0))
    2698             :             te->dataLength = INT_MAX;
    2699             :     }
    2700             : 
    2701        7024 :     destroyPQExpBuffer(copyBuf);
    2702        7024 :     destroyPQExpBuffer(clistBuf);
    2703        7024 : }
    2704             : 
    2705             : /*
    2706             :  * refreshMatViewData -
    2707             :  *    load or refresh the contents of a single materialized view
    2708             :  *
    2709             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2710             :  * statement.
    2711             :  */
    2712             : static void
    2713         676 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2714             : {
    2715         676 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2716             :     PQExpBuffer q;
    2717             : 
    2718             :     /* If the materialized view is not flagged as populated, skip this. */
    2719         676 :     if (!tbinfo->relispopulated)
    2720         136 :         return;
    2721             : 
    2722         540 :     q = createPQExpBuffer();
    2723             : 
    2724         540 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2725         540 :                       fmtQualifiedDumpable(tbinfo));
    2726             : 
    2727         540 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2728         540 :         ArchiveEntry(fout,
    2729             :                      tdinfo->dobj.catId, /* catalog ID */
    2730             :                      tdinfo->dobj.dumpId,    /* dump ID */
    2731         540 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2732             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2733             :                                   .owner = tbinfo->rolname,
    2734             :                                   .description = "MATERIALIZED VIEW DATA",
    2735             :                                   .section = SECTION_POST_DATA,
    2736             :                                   .createStmt = q->data,
    2737             :                                   .deps = tdinfo->dobj.dependencies,
    2738             :                                   .nDeps = tdinfo->dobj.nDeps));
    2739             : 
    2740         540 :     destroyPQExpBuffer(q);
    2741             : }
    2742             : 
    2743             : /*
    2744             :  * getTableData -
    2745             :  *    set up dumpable objects representing the contents of tables
    2746             :  */
    2747             : static void
    2748         300 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2749             : {
    2750             :     int         i;
    2751             : 
    2752       76242 :     for (i = 0; i < numTables; i++)
    2753             :     {
    2754       75942 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2755        1620 :             (!relkind || tblinfo[i].relkind == relkind))
    2756        9916 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2757             :     }
    2758         300 : }
    2759             : 
    2760             : /*
    2761             :  * Make a dumpable object for the data of this specific table
    2762             :  *
    2763             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    2764             :  * table data; the "dump" field in such objects isn't very interesting.
    2765             :  */
    2766             : static void
    2767        9994 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    2768             : {
    2769             :     TableDataInfo *tdinfo;
    2770             : 
    2771             :     /*
    2772             :      * Nothing to do if we already decided to dump the table.  This will
    2773             :      * happen for "config" tables.
    2774             :      */
    2775        9994 :     if (tbinfo->dataObj != NULL)
    2776           2 :         return;
    2777             : 
    2778             :     /* Skip VIEWs (no data to dump) */
    2779        9992 :     if (tbinfo->relkind == RELKIND_VIEW)
    2780         600 :         return;
    2781             :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    2782        9392 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    2783          76 :         (foreign_servers_include_oids.head == NULL ||
    2784           8 :          !simple_oid_list_member(&foreign_servers_include_oids,
    2785             :                                  tbinfo->foreign_server)))
    2786          74 :         return;
    2787             :     /* Skip partitioned tables (data in partitions) */
    2788        9318 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    2789         852 :         return;
    2790             : 
    2791             :     /* Don't dump data in unlogged tables, if so requested */
    2792        8466 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    2793          64 :         dopt->no_unlogged_table_data)
    2794          28 :         return;
    2795             : 
    2796             :     /* Check that the data is not explicitly excluded */
    2797        8438 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    2798             :                                tbinfo->dobj.catId.oid))
    2799          16 :         return;
    2800             : 
    2801             :     /* OK, let's dump it */
    2802        8422 :     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    2803             : 
    2804        8422 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    2805         676 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    2806        7746 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    2807         722 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    2808             :     else
    2809        7024 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    2810             : 
    2811             :     /*
    2812             :      * Note: use tableoid 0 so that this object won't be mistaken for
    2813             :      * something that pg_depend entries apply to.
    2814             :      */
    2815        8422 :     tdinfo->dobj.catId.tableoid = 0;
    2816        8422 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    2817        8422 :     AssignDumpId(&tdinfo->dobj);
    2818        8422 :     tdinfo->dobj.name = tbinfo->dobj.name;
    2819        8422 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    2820        8422 :     tdinfo->tdtable = tbinfo;
    2821        8422 :     tdinfo->filtercond = NULL;   /* might get set later */
    2822        8422 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    2823             : 
    2824             :     /* A TableDataInfo contains data, of course */
    2825        8422 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    2826             : 
    2827        8422 :     tbinfo->dataObj = tdinfo;
    2828             : 
    2829             :     /* Make sure that we'll collect per-column info for this table. */
    2830        8422 :     tbinfo->interesting = true;
    2831             : }
    2832             : 
    2833             : /*
    2834             :  * The refresh for a materialized view must be dependent on the refresh for
    2835             :  * any materialized view that this one is dependent on.
    2836             :  *
    2837             :  * This must be called after all the objects are created, but before they are
    2838             :  * sorted.
    2839             :  */
    2840             : static void
    2841         272 : buildMatViewRefreshDependencies(Archive *fout)
    2842             : {
    2843             :     PQExpBuffer query;
    2844             :     PGresult   *res;
    2845             :     int         ntups,
    2846             :                 i;
    2847             :     int         i_classid,
    2848             :                 i_objid,
    2849             :                 i_refobjid;
    2850             : 
    2851             :     /* No Mat Views before 9.3. */
    2852         272 :     if (fout->remoteVersion < 90300)
    2853           0 :         return;
    2854             : 
    2855         272 :     query = createPQExpBuffer();
    2856             : 
    2857         272 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    2858             :                          "( "
    2859             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    2860             :                          "FROM pg_depend d1 "
    2861             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    2862             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    2863             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    2864             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    2865             :                          "AND d2.objid = r1.oid "
    2866             :                          "AND d2.refobjid <> d1.objid "
    2867             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    2868             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    2869             :                          CppAsString2(RELKIND_VIEW) ") "
    2870             :                          "WHERE d1.classid = 'pg_class'::regclass "
    2871             :                          "UNION "
    2872             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    2873             :                          "FROM w "
    2874             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    2875             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    2876             :                          "AND d3.objid = r3.oid "
    2877             :                          "AND d3.refobjid <> w.refobjid "
    2878             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    2879             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    2880             :                          CppAsString2(RELKIND_VIEW) ") "
    2881             :                          ") "
    2882             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    2883             :                          "FROM w "
    2884             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    2885             : 
    2886         272 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    2887             : 
    2888         272 :     ntups = PQntuples(res);
    2889             : 
    2890         272 :     i_classid = PQfnumber(res, "classid");
    2891         272 :     i_objid = PQfnumber(res, "objid");
    2892         272 :     i_refobjid = PQfnumber(res, "refobjid");
    2893             : 
    2894         788 :     for (i = 0; i < ntups; i++)
    2895             :     {
    2896             :         CatalogId   objId;
    2897             :         CatalogId   refobjId;
    2898             :         DumpableObject *dobj;
    2899             :         DumpableObject *refdobj;
    2900             :         TableInfo  *tbinfo;
    2901             :         TableInfo  *reftbinfo;
    2902             : 
    2903         516 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    2904         516 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    2905         516 :         refobjId.tableoid = objId.tableoid;
    2906         516 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    2907             : 
    2908         516 :         dobj = findObjectByCatalogId(objId);
    2909         516 :         if (dobj == NULL)
    2910          84 :             continue;
    2911             : 
    2912             :         Assert(dobj->objType == DO_TABLE);
    2913         516 :         tbinfo = (TableInfo *) dobj;
    2914             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    2915         516 :         dobj = (DumpableObject *) tbinfo->dataObj;
    2916         516 :         if (dobj == NULL)
    2917          84 :             continue;
    2918             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    2919             : 
    2920         432 :         refdobj = findObjectByCatalogId(refobjId);
    2921         432 :         if (refdobj == NULL)
    2922           0 :             continue;
    2923             : 
    2924             :         Assert(refdobj->objType == DO_TABLE);
    2925         432 :         reftbinfo = (TableInfo *) refdobj;
    2926             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    2927         432 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    2928         432 :         if (refdobj == NULL)
    2929           0 :             continue;
    2930             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    2931             : 
    2932         432 :         addObjectDependency(dobj, refdobj->dumpId);
    2933             : 
    2934         432 :         if (!reftbinfo->relispopulated)
    2935          68 :             tbinfo->relispopulated = false;
    2936             :     }
    2937             : 
    2938         272 :     PQclear(res);
    2939             : 
    2940         272 :     destroyPQExpBuffer(query);
    2941             : }
    2942             : 
    2943             : /*
    2944             :  * getTableDataFKConstraints -
    2945             :  *    add dump-order dependencies reflecting foreign key constraints
    2946             :  *
    2947             :  * This code is executed only in a data-only dump --- in schema+data dumps
    2948             :  * we handle foreign key issues by not creating the FK constraints until
    2949             :  * after the data is loaded.  In a data-only dump, however, we want to
    2950             :  * order the table data objects in such a way that a table's referenced
    2951             :  * tables are restored first.  (In the presence of circular references or
    2952             :  * self-references this may be impossible; we'll detect and complain about
    2953             :  * that during the dependency sorting step.)
    2954             :  */
    2955             : static void
    2956          12 : getTableDataFKConstraints(void)
    2957             : {
    2958             :     DumpableObject **dobjs;
    2959             :     int         numObjs;
    2960             :     int         i;
    2961             : 
    2962             :     /* Search through all the dumpable objects for FK constraints */
    2963          12 :     getDumpableObjects(&dobjs, &numObjs);
    2964       42770 :     for (i = 0; i < numObjs; i++)
    2965             :     {
    2966       42758 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    2967             :         {
    2968          12 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    2969             :             TableInfo  *ftable;
    2970             : 
    2971             :             /* Not interesting unless both tables are to be dumped */
    2972          12 :             if (cinfo->contable == NULL ||
    2973          12 :                 cinfo->contable->dataObj == NULL)
    2974           6 :                 continue;
    2975           6 :             ftable = findTableByOid(cinfo->confrelid);
    2976           6 :             if (ftable == NULL ||
    2977           6 :                 ftable->dataObj == NULL)
    2978           0 :                 continue;
    2979             : 
    2980             :             /*
    2981             :              * Okay, make referencing table's TABLE_DATA object depend on the
    2982             :              * referenced table's TABLE_DATA object.
    2983             :              */
    2984           6 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    2985           6 :                                 ftable->dataObj->dobj.dumpId);
    2986             :         }
    2987             :     }
    2988          12 :     free(dobjs);
    2989          12 : }
    2990             : 
    2991             : 
    2992             : /*
    2993             :  * dumpDatabase:
    2994             :  *  dump the database definition
    2995             :  */
    2996             : static void
    2997         120 : dumpDatabase(Archive *fout)
    2998             : {
    2999         120 :     DumpOptions *dopt = fout->dopt;
    3000         120 :     PQExpBuffer dbQry = createPQExpBuffer();
    3001         120 :     PQExpBuffer delQry = createPQExpBuffer();
    3002         120 :     PQExpBuffer creaQry = createPQExpBuffer();
    3003         120 :     PQExpBuffer labelq = createPQExpBuffer();
    3004         120 :     PGconn     *conn = GetConnection(fout);
    3005             :     PGresult   *res;
    3006             :     int         i_tableoid,
    3007             :                 i_oid,
    3008             :                 i_datname,
    3009             :                 i_datdba,
    3010             :                 i_encoding,
    3011             :                 i_datlocprovider,
    3012             :                 i_collate,
    3013             :                 i_ctype,
    3014             :                 i_datlocale,
    3015             :                 i_daticurules,
    3016             :                 i_frozenxid,
    3017             :                 i_minmxid,
    3018             :                 i_datacl,
    3019             :                 i_acldefault,
    3020             :                 i_datistemplate,
    3021             :                 i_datconnlimit,
    3022             :                 i_datcollversion,
    3023             :                 i_tablespace;
    3024             :     CatalogId   dbCatId;
    3025             :     DumpId      dbDumpId;
    3026             :     DumpableAcl dbdacl;
    3027             :     const char *datname,
    3028             :                *dba,
    3029             :                *encoding,
    3030             :                *datlocprovider,
    3031             :                *collate,
    3032             :                *ctype,
    3033             :                *locale,
    3034             :                *icurules,
    3035             :                *datistemplate,
    3036             :                *datconnlimit,
    3037             :                *tablespace;
    3038             :     uint32      frozenxid,
    3039             :                 minmxid;
    3040             :     char       *qdatname;
    3041             : 
    3042         120 :     pg_log_info("saving database definition");
    3043             : 
    3044             :     /*
    3045             :      * Fetch the database-level properties for this database.
    3046             :      */
    3047         120 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3048             :                          "datdba, "
    3049             :                          "pg_encoding_to_char(encoding) AS encoding, "
    3050             :                          "datcollate, datctype, datfrozenxid, "
    3051             :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3052             :                          "datistemplate, datconnlimit, ");
    3053         120 :     if (fout->remoteVersion >= 90300)
    3054         120 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3055             :     else
    3056           0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3057         120 :     if (fout->remoteVersion >= 170000)
    3058         120 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3059           0 :     else if (fout->remoteVersion >= 150000)
    3060           0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3061             :     else
    3062           0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3063         120 :     if (fout->remoteVersion >= 160000)
    3064         120 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3065             :     else
    3066           0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3067         120 :     appendPQExpBufferStr(dbQry,
    3068             :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3069             :                          "shobj_description(oid, 'pg_database') AS description "
    3070             :                          "FROM pg_database "
    3071             :                          "WHERE datname = current_database()");
    3072             : 
    3073         120 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3074             : 
    3075         120 :     i_tableoid = PQfnumber(res, "tableoid");
    3076         120 :     i_oid = PQfnumber(res, "oid");
    3077         120 :     i_datname = PQfnumber(res, "datname");
    3078         120 :     i_datdba = PQfnumber(res, "datdba");
    3079         120 :     i_encoding = PQfnumber(res, "encoding");
    3080         120 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3081         120 :     i_collate = PQfnumber(res, "datcollate");
    3082         120 :     i_ctype = PQfnumber(res, "datctype");
    3083         120 :     i_datlocale = PQfnumber(res, "datlocale");
    3084         120 :     i_daticurules = PQfnumber(res, "daticurules");
    3085         120 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3086         120 :     i_minmxid = PQfnumber(res, "datminmxid");
    3087         120 :     i_datacl = PQfnumber(res, "datacl");
    3088         120 :     i_acldefault = PQfnumber(res, "acldefault");
    3089         120 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3090         120 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3091         120 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3092         120 :     i_tablespace = PQfnumber(res, "tablespace");
    3093             : 
    3094         120 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3095         120 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3096         120 :     datname = PQgetvalue(res, 0, i_datname);
    3097         120 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3098         120 :     encoding = PQgetvalue(res, 0, i_encoding);
    3099         120 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3100         120 :     collate = PQgetvalue(res, 0, i_collate);
    3101         120 :     ctype = PQgetvalue(res, 0, i_ctype);
    3102         120 :     if (!PQgetisnull(res, 0, i_datlocale))
    3103          28 :         locale = PQgetvalue(res, 0, i_datlocale);
    3104             :     else
    3105          92 :         locale = NULL;
    3106         120 :     if (!PQgetisnull(res, 0, i_daticurules))
    3107           0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3108             :     else
    3109         120 :         icurules = NULL;
    3110         120 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3111         120 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3112         120 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3113         120 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3114         120 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3115         120 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3116         120 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3117             : 
    3118         120 :     qdatname = pg_strdup(fmtId(datname));
    3119             : 
    3120             :     /*
    3121             :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3122             :      * to preserve that), as well as the encoding, locale, and tablespace
    3123             :      * since those can't be altered later.  Other DB properties are left to
    3124             :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3125             :      * reconnecting to the target DB.
    3126             :      */
    3127         120 :     if (dopt->binary_upgrade)
    3128             :     {
    3129          26 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0 OID = %u",
    3130             :                           qdatname, dbCatId.oid);
    3131             :     }
    3132             :     else
    3133             :     {
    3134          94 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3135             :                           qdatname);
    3136             :     }
    3137         120 :     if (strlen(encoding) > 0)
    3138             :     {
    3139         120 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3140         120 :         appendStringLiteralAH(creaQry, encoding, fout);
    3141             :     }
    3142             : 
    3143         120 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3144         120 :     if (datlocprovider[0] == 'b')
    3145          28 :         appendPQExpBufferStr(creaQry, "builtin");
    3146          92 :     else if (datlocprovider[0] == 'c')
    3147          92 :         appendPQExpBufferStr(creaQry, "libc");
    3148           0 :     else if (datlocprovider[0] == 'i')
    3149           0 :         appendPQExpBufferStr(creaQry, "icu");
    3150             :     else
    3151           0 :         pg_fatal("unrecognized locale provider: %s",
    3152             :                  datlocprovider);
    3153             : 
    3154         120 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3155             :     {
    3156         120 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3157         120 :         appendStringLiteralAH(creaQry, collate, fout);
    3158             :     }
    3159             :     else
    3160             :     {
    3161           0 :         if (strlen(collate) > 0)
    3162             :         {
    3163           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3164           0 :             appendStringLiteralAH(creaQry, collate, fout);
    3165             :         }
    3166           0 :         if (strlen(ctype) > 0)
    3167             :         {
    3168           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3169           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3170             :         }
    3171             :     }
    3172         120 :     if (locale)
    3173             :     {
    3174          28 :         if (datlocprovider[0] == 'b')
    3175          28 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3176             :         else
    3177           0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3178             : 
    3179          28 :         appendStringLiteralAH(creaQry, locale, fout);
    3180             :     }
    3181             : 
    3182         120 :     if (icurules)
    3183             :     {
    3184           0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3185           0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3186             :     }
    3187             : 
    3188             :     /*
    3189             :      * For binary upgrade, carry over the collation version.  For normal
    3190             :      * dump/restore, omit the version, so that it is computed upon restore.
    3191             :      */
    3192         120 :     if (dopt->binary_upgrade)
    3193             :     {
    3194          26 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3195             :         {
    3196          26 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3197          26 :             appendStringLiteralAH(creaQry,
    3198             :                                   PQgetvalue(res, 0, i_datcollversion),
    3199             :                                   fout);
    3200             :         }
    3201             :     }
    3202             : 
    3203             :     /*
    3204             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3205             :      * thing; the decision whether to specify a tablespace should be left till
    3206             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3207             :      * label the DATABASE entry with the tablespace and let the normal
    3208             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3209             :      * attention to default_tablespace, so that won't work.
    3210             :      */
    3211         120 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3212           0 :         !dopt->outputNoTablespaces)
    3213           0 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3214             :                           fmtId(tablespace));
    3215         120 :     appendPQExpBufferStr(creaQry, ";\n");
    3216             : 
    3217         120 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3218             :                       qdatname);
    3219             : 
    3220         120 :     dbDumpId = createDumpId();
    3221             : 
    3222         120 :     ArchiveEntry(fout,
    3223             :                  dbCatId,       /* catalog ID */
    3224             :                  dbDumpId,      /* dump ID */
    3225         120 :                  ARCHIVE_OPTS(.tag = datname,
    3226             :                               .owner = dba,
    3227             :                               .description = "DATABASE",
    3228             :                               .section = SECTION_PRE_DATA,
    3229             :                               .createStmt = creaQry->data,
    3230             :                               .dropStmt = delQry->data));
    3231             : 
    3232             :     /* Compute correct tag for archive entry */
    3233         120 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3234             : 
    3235             :     /* Dump DB comment if any */
    3236             :     {
    3237             :         /*
    3238             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3239             :          * cannot use the dumpComment() code used for other database objects.
    3240             :          * Be careful that the ArchiveEntry parameters match that function.
    3241             :          */
    3242         120 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3243             : 
    3244         120 :         if (comment && *comment && !dopt->no_comments)
    3245             :         {
    3246          50 :             resetPQExpBuffer(dbQry);
    3247             : 
    3248             :             /*
    3249             :              * Generates warning when loaded into a differently-named
    3250             :              * database.
    3251             :              */
    3252          50 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3253          50 :             appendStringLiteralAH(dbQry, comment, fout);
    3254          50 :             appendPQExpBufferStr(dbQry, ";\n");
    3255             : 
    3256          50 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3257          50 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3258             :                                       .owner = dba,
    3259             :                                       .description = "COMMENT",
    3260             :                                       .section = SECTION_NONE,
    3261             :                                       .createStmt = dbQry->data,
    3262             :                                       .deps = &dbDumpId,
    3263             :                                       .nDeps = 1));
    3264             :         }
    3265             :     }
    3266             : 
    3267             :     /* Dump DB security label, if enabled */
    3268         120 :     if (!dopt->no_security_labels)
    3269             :     {
    3270             :         PGresult   *shres;
    3271             :         PQExpBuffer seclabelQry;
    3272             : 
    3273         120 :         seclabelQry = createPQExpBuffer();
    3274             : 
    3275         120 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3276         120 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3277         120 :         resetPQExpBuffer(seclabelQry);
    3278         120 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3279         120 :         if (seclabelQry->len > 0)
    3280           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3281           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3282             :                                       .owner = dba,
    3283             :                                       .description = "SECURITY LABEL",
    3284             :                                       .section = SECTION_NONE,
    3285             :                                       .createStmt = seclabelQry->data,
    3286             :                                       .deps = &dbDumpId,
    3287             :                                       .nDeps = 1));
    3288         120 :         destroyPQExpBuffer(seclabelQry);
    3289         120 :         PQclear(shres);
    3290             :     }
    3291             : 
    3292             :     /*
    3293             :      * Dump ACL if any.  Note that we do not support initial privileges
    3294             :      * (pg_init_privs) on databases.
    3295             :      */
    3296         120 :     dbdacl.privtype = 0;
    3297         120 :     dbdacl.initprivs = NULL;
    3298             : 
    3299         120 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3300             :             qdatname, NULL, NULL,
    3301             :             NULL, dba, &dbdacl);
    3302             : 
    3303             :     /*
    3304             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3305             :      * non-default database-level properties.  (The reason this must be
    3306             :      * separate is that we cannot put any additional commands into the TOC
    3307             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3308             :      * in an implicit transaction block, and the backend won't allow CREATE
    3309             :      * DATABASE in that context.)
    3310             :      */
    3311         120 :     resetPQExpBuffer(creaQry);
    3312         120 :     resetPQExpBuffer(delQry);
    3313             : 
    3314         120 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3315           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3316             :                           qdatname, datconnlimit);
    3317             : 
    3318         120 :     if (strcmp(datistemplate, "t") == 0)
    3319             :     {
    3320           8 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3321             :                           qdatname);
    3322             : 
    3323             :         /*
    3324             :          * The backend won't accept DROP DATABASE on a template database.  We
    3325             :          * can deal with that by removing the template marking before the DROP
    3326             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3327             :          * since no such command is currently supported, fake it with a direct
    3328             :          * UPDATE on pg_database.
    3329             :          */
    3330           8 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3331             :                              "SET datistemplate = false WHERE datname = ");
    3332           8 :         appendStringLiteralAH(delQry, datname, fout);
    3333           8 :         appendPQExpBufferStr(delQry, ";\n");
    3334             :     }
    3335             : 
    3336             :     /*
    3337             :      * We do not restore pg_database.dathasloginevt because it is set
    3338             :      * automatically on login event trigger creation.
    3339             :      */
    3340             : 
    3341             :     /* Add database-specific SET options */
    3342         120 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3343             : 
    3344             :     /*
    3345             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3346             :      * entry, too, for lack of a better place.
    3347             :      */
    3348         120 :     if (dopt->binary_upgrade)
    3349             :     {
    3350          26 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3351          26 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3352             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3353             :                           "WHERE datname = ",
    3354             :                           frozenxid, minmxid);
    3355          26 :         appendStringLiteralAH(creaQry, datname, fout);
    3356          26 :         appendPQExpBufferStr(creaQry, ";\n");
    3357             :     }
    3358             : 
    3359         120 :     if (creaQry->len > 0)
    3360          34 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3361          34 :                      ARCHIVE_OPTS(.tag = datname,
    3362             :                                   .owner = dba,
    3363             :                                   .description = "DATABASE PROPERTIES",
    3364             :                                   .section = SECTION_PRE_DATA,
    3365             :                                   .createStmt = creaQry->data,
    3366             :                                   .dropStmt = delQry->data,
    3367             :                                   .deps = &dbDumpId));
    3368             : 
    3369             :     /*
    3370             :      * pg_largeobject comes from the old system intact, so set its
    3371             :      * relfrozenxids, relminmxids and relfilenode.
    3372             :      */
    3373         120 :     if (dopt->binary_upgrade)
    3374             :     {
    3375             :         PGresult   *lo_res;
    3376          26 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3377          26 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3378          26 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3379             :         int         ii_relfrozenxid,
    3380             :                     ii_relfilenode,
    3381             :                     ii_oid,
    3382             :                     ii_relminmxid;
    3383             : 
    3384             :         /*
    3385             :          * pg_largeobject
    3386             :          */
    3387          26 :         if (fout->remoteVersion >= 90300)
    3388          26 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3389             :                               "FROM pg_catalog.pg_class\n"
    3390             :                               "WHERE oid IN (%u, %u);\n",
    3391             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3392             :         else
    3393           0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3394             :                               "FROM pg_catalog.pg_class\n"
    3395             :                               "WHERE oid IN (%u, %u);\n",
    3396             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3397             : 
    3398          26 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3399             : 
    3400          26 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3401          26 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3402          26 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3403          26 :         ii_oid = PQfnumber(lo_res, "oid");
    3404             : 
    3405          26 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3406          26 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3407          78 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3408             :         {
    3409             :             Oid         oid;
    3410             :             RelFileNumber relfilenumber;
    3411             : 
    3412          52 :             appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
    3413             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3414             :                               "WHERE oid = %u;\n",
    3415          52 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3416          52 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3417          52 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3418             : 
    3419          52 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3420          52 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3421             : 
    3422          52 :             if (oid == LargeObjectRelationId)
    3423          26 :                 appendPQExpBuffer(loOutQry,
    3424             :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3425             :                                   relfilenumber);
    3426          26 :             else if (oid == LargeObjectLOidPNIndexId)
    3427          26 :                 appendPQExpBuffer(loOutQry,
    3428             :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3429             :                                   relfilenumber);
    3430             :         }
    3431             : 
    3432          26 :         appendPQExpBufferStr(loOutQry,
    3433             :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3434          26 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3435             : 
    3436          26 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3437          26 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3438             :                                   .description = "pg_largeobject",
    3439             :                                   .section = SECTION_PRE_DATA,
    3440             :                                   .createStmt = loOutQry->data));
    3441             : 
    3442          26 :         PQclear(lo_res);
    3443             : 
    3444          26 :         destroyPQExpBuffer(loFrozenQry);
    3445          26 :         destroyPQExpBuffer(loHorizonQry);
    3446          26 :         destroyPQExpBuffer(loOutQry);
    3447             :     }
    3448             : 
    3449         120 :     PQclear(res);
    3450             : 
    3451         120 :     free(qdatname);
    3452         120 :     destroyPQExpBuffer(dbQry);
    3453         120 :     destroyPQExpBuffer(delQry);
    3454         120 :     destroyPQExpBuffer(creaQry);
    3455         120 :     destroyPQExpBuffer(labelq);
    3456         120 : }
    3457             : 
    3458             : /*
    3459             :  * Collect any database-specific or role-and-database-specific SET options
    3460             :  * for this database, and append them to outbuf.
    3461             :  */
    3462             : static void
    3463         120 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3464             :                    const char *dbname, Oid dboid)
    3465             : {
    3466         120 :     PGconn     *conn = GetConnection(AH);
    3467         120 :     PQExpBuffer buf = createPQExpBuffer();
    3468             :     PGresult   *res;
    3469             : 
    3470             :     /* First collect database-specific options */
    3471         120 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3472             :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3473             :                       dboid);
    3474             : 
    3475         120 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3476             : 
    3477         180 :     for (int i = 0; i < PQntuples(res); i++)
    3478          60 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3479             :                                "DATABASE", dbname, NULL, NULL,
    3480             :                                outbuf);
    3481             : 
    3482         120 :     PQclear(res);
    3483             : 
    3484             :     /* Now look for role-and-database-specific options */
    3485         120 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3486             :                       "FROM pg_db_role_setting s, pg_roles r "
    3487             :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3488             :                       dboid);
    3489             : 
    3490         120 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3491             : 
    3492         120 :     for (int i = 0; i < PQntuples(res); i++)
    3493           0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3494           0 :                                "ROLE", PQgetvalue(res, i, 0),
    3495             :                                "DATABASE", dbname,
    3496             :                                outbuf);
    3497             : 
    3498         120 :     PQclear(res);
    3499             : 
    3500         120 :     destroyPQExpBuffer(buf);
    3501         120 : }
    3502             : 
    3503             : /*
    3504             :  * dumpEncoding: put the correct encoding into the archive
    3505             :  */
    3506             : static void
    3507         304 : dumpEncoding(Archive *AH)
    3508             : {
    3509         304 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3510         304 :     PQExpBuffer qry = createPQExpBuffer();
    3511             : 
    3512         304 :     pg_log_info("saving encoding = %s", encname);
    3513             : 
    3514         304 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3515         304 :     appendStringLiteralAH(qry, encname, AH);
    3516         304 :     appendPQExpBufferStr(qry, ";\n");
    3517             : 
    3518         304 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3519         304 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3520             :                               .description = "ENCODING",
    3521             :                               .section = SECTION_PRE_DATA,
    3522             :                               .createStmt = qry->data));
    3523             : 
    3524         304 :     destroyPQExpBuffer(qry);
    3525         304 : }
    3526             : 
    3527             : 
    3528             : /*
    3529             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3530             :  */
    3531             : static void
    3532         304 : dumpStdStrings(Archive *AH)
    3533             : {
    3534         304 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3535         304 :     PQExpBuffer qry = createPQExpBuffer();
    3536             : 
    3537         304 :     pg_log_info("saving standard_conforming_strings = %s",
    3538             :                 stdstrings);
    3539             : 
    3540         304 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3541             :                       stdstrings);
    3542             : 
    3543         304 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3544         304 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3545             :                               .description = "STDSTRINGS",
    3546             :                               .section = SECTION_PRE_DATA,
    3547             :                               .createStmt = qry->data));
    3548             : 
    3549         304 :     destroyPQExpBuffer(qry);
    3550         304 : }
    3551             : 
    3552             : /*
    3553             :  * dumpSearchPath: record the active search_path in the archive
    3554             :  */
    3555             : static void
    3556         304 : dumpSearchPath(Archive *AH)
    3557             : {
    3558         304 :     PQExpBuffer qry = createPQExpBuffer();
    3559         304 :     PQExpBuffer path = createPQExpBuffer();
    3560             :     PGresult   *res;
    3561         304 :     char      **schemanames = NULL;
    3562         304 :     int         nschemanames = 0;
    3563             :     int         i;
    3564             : 
    3565             :     /*
    3566             :      * We use the result of current_schemas(), not the search_path GUC,
    3567             :      * because that might contain wildcards such as "$user", which won't
    3568             :      * necessarily have the same value during restore.  Also, this way avoids
    3569             :      * listing schemas that may appear in search_path but not actually exist,
    3570             :      * which seems like a prudent exclusion.
    3571             :      */
    3572         304 :     res = ExecuteSqlQueryForSingleRow(AH,
    3573             :                                       "SELECT pg_catalog.current_schemas(false)");
    3574             : 
    3575         304 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3576           0 :         pg_fatal("could not parse result of current_schemas()");
    3577             : 
    3578             :     /*
    3579             :      * We use set_config(), not a simple "SET search_path" command, because
    3580             :      * the latter has less-clean behavior if the search path is empty.  While
    3581             :      * that's likely to get fixed at some point, it seems like a good idea to
    3582             :      * be as backwards-compatible as possible in what we put into archives.
    3583             :      */
    3584         304 :     for (i = 0; i < nschemanames; i++)
    3585             :     {
    3586           0 :         if (i > 0)
    3587           0 :             appendPQExpBufferStr(path, ", ");
    3588           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3589             :     }
    3590             : 
    3591         304 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3592         304 :     appendStringLiteralAH(qry, path->data, AH);
    3593         304 :     appendPQExpBufferStr(qry, ", false);\n");
    3594             : 
    3595         304 :     pg_log_info("saving search_path = %s", path->data);
    3596             : 
    3597         304 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3598         304 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3599             :                               .description = "SEARCHPATH",
    3600             :                               .section = SECTION_PRE_DATA,
    3601             :                               .createStmt = qry->data));
    3602             : 
    3603             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3604         304 :     AH->searchpath = pg_strdup(qry->data);
    3605             : 
    3606         304 :     free(schemanames);
    3607         304 :     PQclear(res);
    3608         304 :     destroyPQExpBuffer(qry);
    3609         304 :     destroyPQExpBuffer(path);
    3610         304 : }
    3611             : 
    3612             : 
    3613             : /*
    3614             :  * getLOs:
    3615             :  *  Collect schema-level data about large objects
    3616             :  */
    3617             : static void
    3618         256 : getLOs(Archive *fout)
    3619             : {
    3620         256 :     DumpOptions *dopt = fout->dopt;
    3621         256 :     PQExpBuffer loQry = createPQExpBuffer();
    3622             :     PGresult   *res;
    3623             :     int         ntups;
    3624             :     int         i;
    3625             :     int         n;
    3626             :     int         i_oid;
    3627             :     int         i_lomowner;
    3628             :     int         i_lomacl;
    3629             :     int         i_acldefault;
    3630             : 
    3631         256 :     pg_log_info("reading large objects");
    3632             : 
    3633             :     /*
    3634             :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3635             :      * with the same owner/ACL appear together.
    3636             :      */
    3637         256 :     appendPQExpBufferStr(loQry,
    3638             :                          "SELECT oid, lomowner, lomacl, "
    3639             :                          "acldefault('L', lomowner) AS acldefault "
    3640             :                          "FROM pg_largeobject_metadata "
    3641             :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3642             : 
    3643         256 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3644             : 
    3645         256 :     i_oid = PQfnumber(res, "oid");
    3646         256 :     i_lomowner = PQfnumber(res, "lomowner");
    3647         256 :     i_lomacl = PQfnumber(res, "lomacl");
    3648         256 :     i_acldefault = PQfnumber(res, "acldefault");
    3649             : 
    3650         256 :     ntups = PQntuples(res);
    3651             : 
    3652             :     /*
    3653             :      * Group the blobs into suitably-sized groups that have the same owner and
    3654             :      * ACL setting, and build a metadata and a data DumpableObject for each
    3655             :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3656             :      * groups also share initprivs settings, since the DumpableObject only has
    3657             :      * room for one.)  i is the index of the first tuple in the current group,
    3658             :      * and n is the number of tuples we include in the group.
    3659             :      */
    3660         402 :     for (i = 0; i < ntups; i += n)
    3661             :     {
    3662         146 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3663         146 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3664         146 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    3665             :         LoInfo     *loinfo;
    3666             :         DumpableObject *lodata;
    3667             :         char        namebuf[64];
    3668             : 
    3669             :         /* Scan to find first tuple not to be included in group */
    3670         146 :         n = 1;
    3671         166 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    3672             :         {
    3673          88 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    3674          88 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    3675             :                 break;
    3676          20 :             n++;
    3677             :         }
    3678             : 
    3679             :         /* Build the metadata DumpableObject */
    3680         146 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    3681             : 
    3682         146 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    3683         146 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    3684         146 :         loinfo->dobj.catId.oid = thisoid;
    3685         146 :         AssignDumpId(&loinfo->dobj);
    3686             : 
    3687         146 :         if (n > 1)
    3688          10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    3689          10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    3690             :         else
    3691         136 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    3692         146 :         loinfo->dobj.name = pg_strdup(namebuf);
    3693         146 :         loinfo->dacl.acl = pg_strdup(thisacl);
    3694         146 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    3695         146 :         loinfo->dacl.privtype = 0;
    3696         146 :         loinfo->dacl.initprivs = NULL;
    3697         146 :         loinfo->rolname = getRoleName(thisowner);
    3698         146 :         loinfo->numlos = n;
    3699         146 :         loinfo->looids[0] = thisoid;
    3700             :         /* Collect OIDs of the remaining blobs in this group */
    3701         166 :         for (int k = 1; k < n; k++)
    3702             :         {
    3703             :             CatalogId   extraID;
    3704             : 
    3705          20 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    3706             : 
    3707             :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    3708          20 :             extraID.tableoid = LargeObjectRelationId;
    3709          20 :             extraID.oid = loinfo->looids[k];
    3710          20 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    3711             :         }
    3712             : 
    3713             :         /* LOs have data */
    3714         146 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3715             : 
    3716             :         /* Mark whether LO group has a non-empty ACL */
    3717         146 :         if (!PQgetisnull(res, i, i_lomacl))
    3718          68 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    3719             : 
    3720             :         /*
    3721             :          * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
    3722             :          * as it will be copied by pg_upgrade, which simply copies the
    3723             :          * pg_largeobject table. We *do* however dump out anything but the
    3724             :          * data, as pg_upgrade copies just pg_largeobject, but not
    3725             :          * pg_largeobject_metadata, after the dump is restored.
    3726             :          */
    3727         146 :         if (dopt->binary_upgrade)
    3728           6 :             loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
    3729             : 
    3730             :         /*
    3731             :          * Create a "BLOBS" data item for the group, too. This is just a
    3732             :          * placeholder for sorting; it carries no data now.
    3733             :          */
    3734         146 :         lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    3735         146 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    3736         146 :         lodata->catId = nilCatalogId;
    3737         146 :         AssignDumpId(lodata);
    3738         146 :         lodata->name = pg_strdup(namebuf);
    3739         146 :         lodata->components |= DUMP_COMPONENT_DATA;
    3740             :         /* Set up explicit dependency from data to metadata */
    3741         146 :         lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    3742         146 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    3743         146 :         lodata->nDeps = lodata->allocDeps = 1;
    3744             :     }
    3745             : 
    3746         256 :     PQclear(res);
    3747         256 :     destroyPQExpBuffer(loQry);
    3748         256 : }
    3749             : 
    3750             : /*
    3751             :  * dumpLO
    3752             :  *
    3753             :  * dump the definition (metadata) of the given large object group
    3754             :  */
    3755             : static void
    3756         146 : dumpLO(Archive *fout, const LoInfo *loinfo)
    3757             : {
    3758         146 :     PQExpBuffer cquery = createPQExpBuffer();
    3759             : 
    3760             :     /*
    3761             :      * The "definition" is just a newline-separated list of OIDs.  We need to
    3762             :      * put something into the dropStmt too, but it can just be a comment.
    3763             :      */
    3764         312 :     for (int i = 0; i < loinfo->numlos; i++)
    3765         166 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    3766             : 
    3767         146 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    3768         146 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    3769         146 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    3770             :                                   .owner = loinfo->rolname,
    3771             :                                   .description = "BLOB METADATA",
    3772             :                                   .section = SECTION_DATA,
    3773             :                                   .createStmt = cquery->data,
    3774             :                                   .dropStmt = "-- dummy"));
    3775             : 
    3776             :     /*
    3777             :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    3778             :      * enough that it's okay to generate retail TOC entries for them.
    3779             :      */
    3780         146 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    3781             :                              DUMP_COMPONENT_SECLABEL))
    3782             :     {
    3783         176 :         for (int i = 0; i < loinfo->numlos; i++)
    3784             :         {
    3785             :             CatalogId   catId;
    3786             :             char        namebuf[32];
    3787             : 
    3788             :             /* Build identifying info for this blob */
    3789          98 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    3790          98 :             catId.oid = loinfo->looids[i];
    3791          98 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    3792             : 
    3793          98 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    3794          98 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    3795             :                             NULL, loinfo->rolname,
    3796             :                             catId, 0, loinfo->dobj.dumpId);
    3797             : 
    3798          98 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    3799           0 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    3800             :                              NULL, loinfo->rolname,
    3801             :                              catId, 0, loinfo->dobj.dumpId);
    3802             :         }
    3803             :     }
    3804             : 
    3805             :     /*
    3806             :      * Dump the ACLs if any (remember that all blobs in the group will have
    3807             :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    3808             :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    3809             :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    3810             :      * string to emit a mutated version for each blob.
    3811             :      */
    3812         146 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    3813             :     {
    3814             :         char        namebuf[32];
    3815             : 
    3816             :         /* Build identifying info for the first blob */
    3817          68 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    3818             : 
    3819          68 :         if (loinfo->numlos > 1)
    3820             :         {
    3821             :             char        tagbuf[64];
    3822             : 
    3823           0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    3824           0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    3825             : 
    3826           0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    3827             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    3828             :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    3829             :         }
    3830             :         else
    3831             :         {
    3832          68 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    3833             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    3834             :                     NULL, loinfo->rolname, &loinfo->dacl);
    3835             :         }
    3836             :     }
    3837             : 
    3838         146 :     destroyPQExpBuffer(cquery);
    3839         146 : }
    3840             : 
    3841             : /*
    3842             :  * dumpLOs:
    3843             :  *  dump the data contents of the large objects in the given group
    3844             :  */
    3845             : static int
    3846         132 : dumpLOs(Archive *fout, const void *arg)
    3847             : {
    3848         132 :     const LoInfo *loinfo = (const LoInfo *) arg;
    3849         132 :     PGconn     *conn = GetConnection(fout);
    3850             :     char        buf[LOBBUFSIZE];
    3851             : 
    3852         132 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    3853             : 
    3854         280 :     for (int i = 0; i < loinfo->numlos; i++)
    3855             :     {
    3856         148 :         Oid         loOid = loinfo->looids[i];
    3857             :         int         loFd;
    3858             :         int         cnt;
    3859             : 
    3860             :         /* Open the LO */
    3861         148 :         loFd = lo_open(conn, loOid, INV_READ);
    3862         148 :         if (loFd == -1)
    3863           0 :             pg_fatal("could not open large object %u: %s",
    3864             :                      loOid, PQerrorMessage(conn));
    3865             : 
    3866         148 :         StartLO(fout, loOid);
    3867             : 
    3868             :         /* Now read it in chunks, sending data to archive */
    3869             :         do
    3870             :         {
    3871         226 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    3872         226 :             if (cnt < 0)
    3873           0 :                 pg_fatal("error reading large object %u: %s",
    3874             :                          loOid, PQerrorMessage(conn));
    3875             : 
    3876         226 :             WriteData(fout, buf, cnt);
    3877         226 :         } while (cnt > 0);
    3878             : 
    3879         148 :         lo_close(conn, loFd);
    3880             : 
    3881         148 :         EndLO(fout, loOid);
    3882             :     }
    3883             : 
    3884         132 :     return 1;
    3885             : }
    3886             : 
    3887             : /*
    3888             :  * getPolicies
    3889             :  *    get information about all RLS policies on dumpable tables.
    3890             :  */
    3891             : void
    3892         304 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    3893             : {
    3894             :     PQExpBuffer query;
    3895             :     PQExpBuffer tbloids;
    3896             :     PGresult   *res;
    3897             :     PolicyInfo *polinfo;
    3898             :     int         i_oid;
    3899             :     int         i_tableoid;
    3900             :     int         i_polrelid;
    3901             :     int         i_polname;
    3902             :     int         i_polcmd;
    3903             :     int         i_polpermissive;
    3904             :     int         i_polroles;
    3905             :     int         i_polqual;
    3906             :     int         i_polwithcheck;
    3907             :     int         i,
    3908             :                 j,
    3909             :                 ntups;
    3910             : 
    3911             :     /* No policies before 9.5 */
    3912         304 :     if (fout->remoteVersion < 90500)
    3913           0 :         return;
    3914             : 
    3915         304 :     query = createPQExpBuffer();
    3916         304 :     tbloids = createPQExpBuffer();
    3917             : 
    3918             :     /*
    3919             :      * Identify tables of interest, and check which ones have RLS enabled.
    3920             :      */
    3921         304 :     appendPQExpBufferChar(tbloids, '{');
    3922       77210 :     for (i = 0; i < numTables; i++)
    3923             :     {
    3924       76906 :         TableInfo  *tbinfo = &tblinfo[i];
    3925             : 
    3926             :         /* Ignore row security on tables not to be dumped */
    3927       76906 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    3928       65382 :             continue;
    3929             : 
    3930             :         /* It can't have RLS or policies if it's not a table */
    3931       11524 :         if (tbinfo->relkind != RELKIND_RELATION &&
    3932        3236 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    3933        2212 :             continue;
    3934             : 
    3935             :         /* Add it to the list of table OIDs to be probed below */
    3936        9312 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    3937        9120 :             appendPQExpBufferChar(tbloids, ',');
    3938        9312 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    3939             : 
    3940             :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    3941        9312 :         if (tbinfo->rowsec)
    3942             :         {
    3943         104 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    3944             : 
    3945             :             /*
    3946             :              * We represent RLS being enabled on a table by creating a
    3947             :              * PolicyInfo object with null polname.
    3948             :              *
    3949             :              * Note: use tableoid 0 so that this object won't be mistaken for
    3950             :              * something that pg_depend entries apply to.
    3951             :              */
    3952         104 :             polinfo = pg_malloc(sizeof(PolicyInfo));
    3953         104 :             polinfo->dobj.objType = DO_POLICY;
    3954         104 :             polinfo->dobj.catId.tableoid = 0;
    3955         104 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    3956         104 :             AssignDumpId(&polinfo->dobj);
    3957         104 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    3958         104 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    3959         104 :             polinfo->poltable = tbinfo;
    3960         104 :             polinfo->polname = NULL;
    3961         104 :             polinfo->polcmd = '\0';
    3962         104 :             polinfo->polpermissive = 0;
    3963         104 :             polinfo->polroles = NULL;
    3964         104 :             polinfo->polqual = NULL;
    3965         104 :             polinfo->polwithcheck = NULL;
    3966             :         }
    3967             :     }
    3968         304 :     appendPQExpBufferChar(tbloids, '}');
    3969             : 
    3970             :     /*
    3971             :      * Now, read all RLS policies belonging to the tables of interest, and
    3972             :      * create PolicyInfo objects for them.  (Note that we must filter the
    3973             :      * results server-side not locally, because we dare not apply pg_get_expr
    3974             :      * to tables we don't have lock on.)
    3975             :      */
    3976         304 :     pg_log_info("reading row-level security policies");
    3977             : 
    3978         304 :     printfPQExpBuffer(query,
    3979             :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    3980         304 :     if (fout->remoteVersion >= 100000)
    3981         304 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    3982             :     else
    3983           0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    3984         304 :     appendPQExpBuffer(query,
    3985             :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    3986             :                       "   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, "
    3987             :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    3988             :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    3989             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    3990             :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    3991             :                       tbloids->data);
    3992             : 
    3993         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3994             : 
    3995         304 :     ntups = PQntuples(res);
    3996         304 :     if (ntups > 0)
    3997             :     {
    3998          84 :         i_oid = PQfnumber(res, "oid");
    3999          84 :         i_tableoid = PQfnumber(res, "tableoid");
    4000          84 :         i_polrelid = PQfnumber(res, "polrelid");
    4001          84 :         i_polname = PQfnumber(res, "polname");
    4002          84 :         i_polcmd = PQfnumber(res, "polcmd");
    4003          84 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4004          84 :         i_polroles = PQfnumber(res, "polroles");
    4005          84 :         i_polqual = PQfnumber(res, "polqual");
    4006          84 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4007             : 
    4008          84 :         polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    4009             : 
    4010         618 :         for (j = 0; j < ntups; j++)
    4011             :         {
    4012         534 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4013         534 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4014             : 
    4015         534 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4016             : 
    4017         534 :             polinfo[j].dobj.objType = DO_POLICY;
    4018         534 :             polinfo[j].dobj.catId.tableoid =
    4019         534 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4020         534 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4021         534 :             AssignDumpId(&polinfo[j].dobj);
    4022         534 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4023         534 :             polinfo[j].poltable = tbinfo;
    4024         534 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4025         534 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4026             : 
    4027         534 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4028         534 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4029             : 
    4030         534 :             if (PQgetisnull(res, j, i_polroles))
    4031         238 :                 polinfo[j].polroles = NULL;
    4032             :             else
    4033         296 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4034             : 
    4035         534 :             if (PQgetisnull(res, j, i_polqual))
    4036          74 :                 polinfo[j].polqual = NULL;
    4037             :             else
    4038         460 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4039             : 
    4040         534 :             if (PQgetisnull(res, j, i_polwithcheck))
    4041         282 :                 polinfo[j].polwithcheck = NULL;
    4042             :             else
    4043         252 :                 polinfo[j].polwithcheck
    4044         252 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4045             :         }
    4046             :     }
    4047             : 
    4048         304 :     PQclear(res);
    4049             : 
    4050         304 :     destroyPQExpBuffer(query);
    4051         304 :     destroyPQExpBuffer(tbloids);
    4052             : }
    4053             : 
    4054             : /*
    4055             :  * dumpPolicy
    4056             :  *    dump the definition of the given policy
    4057             :  */
    4058             : static void
    4059         638 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4060             : {
    4061         638 :     DumpOptions *dopt = fout->dopt;
    4062         638 :     TableInfo  *tbinfo = polinfo->poltable;
    4063             :     PQExpBuffer query;
    4064             :     PQExpBuffer delqry;
    4065             :     PQExpBuffer polprefix;
    4066             :     char       *qtabname;
    4067             :     const char *cmd;
    4068             :     char       *tag;
    4069             : 
    4070             :     /* Do nothing in data-only dump */
    4071         638 :     if (dopt->dataOnly)
    4072          56 :         return;
    4073             : 
    4074             :     /*
    4075             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4076             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4077             :      * ROW LEVEL SECURITY.
    4078             :      */
    4079         582 :     if (polinfo->polname == NULL)
    4080             :     {
    4081          96 :         query = createPQExpBuffer();
    4082             : 
    4083          96 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4084          96 :                           fmtQualifiedDumpable(tbinfo));
    4085             : 
    4086             :         /*
    4087             :          * We must emit the ROW SECURITY object's dependency on its table
    4088             :          * explicitly, because it will not match anything in pg_depend (unlike
    4089             :          * the case for other PolicyInfo objects).
    4090             :          */
    4091          96 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4092          96 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4093          96 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4094             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4095             :                                       .owner = tbinfo->rolname,
    4096             :                                       .description = "ROW SECURITY",
    4097             :                                       .section = SECTION_POST_DATA,
    4098             :                                       .createStmt = query->data,
    4099             :                                       .deps = &(tbinfo->dobj.dumpId),
    4100             :                                       .nDeps = 1));
    4101             : 
    4102          96 :         destroyPQExpBuffer(query);
    4103          96 :         return;
    4104             :     }
    4105             : 
    4106         486 :     if (polinfo->polcmd == '*')
    4107         162 :         cmd = "";
    4108         324 :     else if (polinfo->polcmd == 'r')
    4109          86 :         cmd = " FOR SELECT";
    4110         238 :     else if (polinfo->polcmd == 'a')
    4111          66 :         cmd = " FOR INSERT";
    4112         172 :     else if (polinfo->polcmd == 'w')
    4113          86 :         cmd = " FOR UPDATE";
    4114          86 :     else if (polinfo->polcmd == 'd')
    4115          86 :         cmd = " FOR DELETE";
    4116             :     else
    4117           0 :         pg_fatal("unexpected policy command type: %c",
    4118             :                  polinfo->polcmd);
    4119             : 
    4120         486 :     query = createPQExpBuffer();
    4121         486 :     delqry = createPQExpBuffer();
    4122         486 :     polprefix = createPQExpBuffer();
    4123             : 
    4124         486 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4125             : 
    4126         486 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4127             : 
    4128         486 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4129         486 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4130             : 
    4131         486 :     if (polinfo->polroles != NULL)
    4132         264 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4133             : 
    4134         486 :     if (polinfo->polqual != NULL)
    4135         420 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4136             : 
    4137         486 :     if (polinfo->polwithcheck != NULL)
    4138         228 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4139             : 
    4140         486 :     appendPQExpBufferStr(query, ";\n");
    4141             : 
    4142         486 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4143         486 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4144             : 
    4145         486 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4146         486 :                       fmtId(polinfo->polname));
    4147             : 
    4148         486 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4149             : 
    4150         486 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4151         486 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4152         486 :                      ARCHIVE_OPTS(.tag = tag,
    4153             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4154             :                                   .owner = tbinfo->rolname,
    4155             :                                   .description = "POLICY",
    4156             :                                   .section = SECTION_POST_DATA,
    4157             :                                   .createStmt = query->data,
    4158             :                                   .dropStmt = delqry->data));
    4159             : 
    4160         486 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4161           0 :         dumpComment(fout, polprefix->data, qtabname,
    4162           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4163             :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4164             : 
    4165         486 :     free(tag);
    4166         486 :     destroyPQExpBuffer(query);
    4167         486 :     destroyPQExpBuffer(delqry);
    4168         486 :     destroyPQExpBuffer(polprefix);
    4169         486 :     free(qtabname);
    4170             : }
    4171             : 
    4172             : /*
    4173             :  * getPublications
    4174             :  *    get information about publications
    4175             :  */
    4176             : PublicationInfo *
    4177         304 : getPublications(Archive *fout, int *numPublications)
    4178             : {
    4179         304 :     DumpOptions *dopt = fout->dopt;
    4180             :     PQExpBuffer query;
    4181             :     PGresult   *res;
    4182             :     PublicationInfo *pubinfo;
    4183             :     int         i_tableoid;
    4184             :     int         i_oid;
    4185             :     int         i_pubname;
    4186             :     int         i_pubowner;
    4187             :     int         i_puballtables;
    4188             :     int         i_pubinsert;
    4189             :     int         i_pubupdate;
    4190             :     int         i_pubdelete;
    4191             :     int         i_pubtruncate;
    4192             :     int         i_pubviaroot;
    4193             :     int         i,
    4194             :                 ntups;
    4195             : 
    4196         304 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4197             :     {
    4198           0 :         *numPublications = 0;
    4199           0 :         return NULL;
    4200             :     }
    4201             : 
    4202         304 :     query = createPQExpBuffer();
    4203             : 
    4204         304 :     resetPQExpBuffer(query);
    4205             : 
    4206             :     /* Get the publications. */
    4207         304 :     if (fout->remoteVersion >= 130000)
    4208         304 :         appendPQExpBufferStr(query,
    4209             :                              "SELECT p.tableoid, p.oid, p.pubname, "
    4210             :                              "p.pubowner, "
    4211             :                              "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, p.pubviaroot "
    4212             :                              "FROM pg_publication p");
    4213           0 :     else if (fout->remoteVersion >= 110000)
    4214           0 :         appendPQExpBufferStr(query,
    4215             :                              "SELECT p.tableoid, p.oid, p.pubname, "
    4216             :                              "p.pubowner, "
    4217             :                              "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, false AS pubviaroot "
    4218             :                              "FROM pg_publication p");
    4219             :     else
    4220           0 :         appendPQExpBufferStr(query,
    4221             :                              "SELECT p.tableoid, p.oid, p.pubname, "
    4222             :                              "p.pubowner, "
    4223             :                              "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate, false AS pubviaroot "
    4224             :                              "FROM pg_publication p");
    4225             : 
    4226         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4227             : 
    4228         304 :     ntups = PQntuples(res);
    4229             : 
    4230         304 :     i_tableoid = PQfnumber(res, "tableoid");
    4231         304 :     i_oid = PQfnumber(res, "oid");
    4232         304 :     i_pubname = PQfnumber(res, "pubname");
    4233         304 :     i_pubowner = PQfnumber(res, "pubowner");
    4234         304 :     i_puballtables = PQfnumber(res, "puballtables");
    4235         304 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4236         304 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4237         304 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4238         304 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4239         304 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4240             : 
    4241         304 :     pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    4242             : 
    4243         650 :     for (i = 0; i < ntups; i++)
    4244             :     {
    4245         346 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4246         346 :         pubinfo[i].dobj.catId.tableoid =
    4247         346 :             atooid(PQgetvalue(res, i, i_tableoid));
    4248         346 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4249         346 :         AssignDumpId(&pubinfo[i].dobj);
    4250         346 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4251         346 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4252         346 :         pubinfo[i].puballtables =
    4253         346 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4254         346 :         pubinfo[i].pubinsert =
    4255         346 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4256         346 :         pubinfo[i].pubupdate =
    4257         346 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4258         346 :         pubinfo[i].pubdelete =
    4259         346 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4260         346 :         pubinfo[i].pubtruncate =
    4261         346 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4262         346 :         pubinfo[i].pubviaroot =
    4263         346 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4264             : 
    4265             :         /* Decide whether we want to dump it */
    4266         346 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4267             :     }
    4268         304 :     PQclear(res);
    4269             : 
    4270         304 :     destroyPQExpBuffer(query);
    4271             : 
    4272         304 :     *numPublications = ntups;
    4273         304 :     return pubinfo;
    4274             : }
    4275             : 
    4276             : /*
    4277             :  * dumpPublication
    4278             :  *    dump the definition of the given publication
    4279             :  */
    4280             : static void
    4281         282 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4282             : {
    4283         282 :     DumpOptions *dopt = fout->dopt;
    4284             :     PQExpBuffer delq;
    4285             :     PQExpBuffer query;
    4286             :     char       *qpubname;
    4287         282 :     bool        first = true;
    4288             : 
    4289             :     /* Do nothing in data-only dump */
    4290         282 :     if (dopt->dataOnly)
    4291          24 :         return;
    4292             : 
    4293         258 :     delq = createPQExpBuffer();
    4294         258 :     query = createPQExpBuffer();
    4295             : 
    4296         258 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4297             : 
    4298         258 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4299             :                       qpubname);
    4300             : 
    4301         258 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4302             :                       qpubname);
    4303             : 
    4304         258 :     if (pubinfo->puballtables)
    4305          66 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4306             : 
    4307         258 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4308         258 :     if (pubinfo->pubinsert)
    4309             :     {
    4310         194 :         appendPQExpBufferStr(query, "insert");
    4311         194 :         first = false;
    4312             :     }
    4313             : 
    4314         258 :     if (pubinfo->pubupdate)
    4315             :     {
    4316         194 :         if (!first)
    4317         194 :             appendPQExpBufferStr(query, ", ");
    4318             : 
    4319         194 :         appendPQExpBufferStr(query, "update");
    4320         194 :         first = false;
    4321             :     }
    4322             : 
    4323         258 :     if (pubinfo->pubdelete)
    4324             :     {
    4325         194 :         if (!first)
    4326         194 :             appendPQExpBufferStr(query, ", ");
    4327             : 
    4328         194 :         appendPQExpBufferStr(query, "delete");
    4329         194 :         first = false;
    4330             :     }
    4331             : 
    4332         258 :     if (pubinfo->pubtruncate)
    4333             :     {
    4334         194 :         if (!first)
    4335         194 :             appendPQExpBufferStr(query, ", ");
    4336             : 
    4337         194 :         appendPQExpBufferStr(query, "truncate");
    4338         194 :         first = false;
    4339             :     }
    4340             : 
    4341         258 :     appendPQExpBufferChar(query, '\'');
    4342             : 
    4343         258 :     if (pubinfo->pubviaroot)
    4344           0 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4345             : 
    4346         258 :     appendPQExpBufferStr(query, ");\n");
    4347             : 
    4348         258 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4349         258 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4350         258 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4351             :                                   .owner = pubinfo->rolname,
    4352             :                                   .description = "PUBLICATION",
    4353             :                                   .section = SECTION_POST_DATA,
    4354             :                                   .createStmt = query->data,
    4355             :                                   .dropStmt = delq->data));
    4356             : 
    4357         258 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4358          64 :         dumpComment(fout, "PUBLICATION", qpubname,
    4359             :                     NULL, pubinfo->rolname,
    4360             :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4361             : 
    4362         258 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4363           0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4364             :                      NULL, pubinfo->rolname,
    4365             :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4366             : 
    4367         258 :     destroyPQExpBuffer(delq);
    4368         258 :     destroyPQExpBuffer(query);
    4369         258 :     free(qpubname);
    4370             : }
    4371             : 
    4372             : /*
    4373             :  * getPublicationNamespaces
    4374             :  *    get information about publication membership for dumpable schemas.
    4375             :  */
    4376             : void
    4377         304 : getPublicationNamespaces(Archive *fout)
    4378             : {
    4379             :     PQExpBuffer query;
    4380             :     PGresult   *res;
    4381             :     PublicationSchemaInfo *pubsinfo;
    4382         304 :     DumpOptions *dopt = fout->dopt;
    4383             :     int         i_tableoid;
    4384             :     int         i_oid;
    4385             :     int         i_pnpubid;
    4386             :     int         i_pnnspid;
    4387             :     int         i,
    4388             :                 j,
    4389             :                 ntups;
    4390             : 
    4391         304 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4392           0 :         return;
    4393             : 
    4394         304 :     query = createPQExpBuffer();
    4395             : 
    4396             :     /* Collect all publication membership info. */
    4397         304 :     appendPQExpBufferStr(query,
    4398             :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4399             :                          "FROM pg_catalog.pg_publication_namespace");
    4400         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4401             : 
    4402         304 :     ntups = PQntuples(res);
    4403             : 
    4404         304 :     i_tableoid = PQfnumber(res, "tableoid");
    4405         304 :     i_oid = PQfnumber(res, "oid");
    4406         304 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4407         304 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4408             : 
    4409             :     /* this allocation may be more than we need */
    4410         304 :     pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
    4411         304 :     j = 0;
    4412             : 
    4413         476 :     for (i = 0; i < ntups; i++)
    4414             :     {
    4415         172 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4416         172 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4417             :         PublicationInfo *pubinfo;
    4418             :         NamespaceInfo *nspinfo;
    4419             : 
    4420             :         /*
    4421             :          * Ignore any entries for which we aren't interested in either the
    4422             :          * publication or the rel.
    4423             :          */
    4424         172 :         pubinfo = findPublicationByOid(pnpubid);
    4425         172 :         if (pubinfo == NULL)
    4426           0 :             continue;
    4427         172 :         nspinfo = findNamespaceByOid(pnnspid);
    4428         172 :         if (nspinfo == NULL)
    4429           0 :             continue;
    4430             : 
    4431             :         /*
    4432             :          * We always dump publication namespaces unless the corresponding
    4433             :          * namespace is excluded from the dump.
    4434             :          */
    4435         172 :         if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
    4436          30 :             continue;
    4437             : 
    4438             :         /* OK, make a DumpableObject for this relationship */
    4439         142 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4440         142 :         pubsinfo[j].dobj.catId.tableoid =
    4441         142 :             atooid(PQgetvalue(res, i, i_tableoid));
    4442         142 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4443         142 :         AssignDumpId(&pubsinfo[j].dobj);
    4444         142 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4445         142 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4446         142 :         pubsinfo[j].publication = pubinfo;
    4447         142 :         pubsinfo[j].pubschema = nspinfo;
    4448             : 
    4449             :         /* Decide whether we want to dump it */
    4450         142 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4451             : 
    4452         142 :         j++;
    4453             :     }
    4454             : 
    4455         304 :     PQclear(res);
    4456         304 :     destroyPQExpBuffer(query);
    4457             : }
    4458             : 
    4459             : /*
    4460             :  * getPublicationTables
    4461             :  *    get information about publication membership for dumpable tables.
    4462             :  */
    4463             : void
    4464         304 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4465             : {
    4466             :     PQExpBuffer query;
    4467             :     PGresult   *res;
    4468             :     PublicationRelInfo *pubrinfo;
    4469         304 :     DumpOptions *dopt = fout->dopt;
    4470             :     int         i_tableoid;
    4471             :     int         i_oid;
    4472             :     int         i_prpubid;
    4473             :     int         i_prrelid;
    4474             :     int         i_prrelqual;
    4475             :     int         i_prattrs;
    4476             :     int         i,
    4477             :                 j,
    4478             :                 ntups;
    4479             : 
    4480         304 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4481           0 :         return;
    4482             : 
    4483         304 :     query = createPQExpBuffer();
    4484             : 
    4485             :     /* Collect all publication membership info. */
    4486         304 :     if (fout->remoteVersion >= 150000)
    4487         304 :         appendPQExpBufferStr(query,
    4488             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4489             :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4490             :                              "(CASE\n"
    4491             :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4492             :                              "    (SELECT array_agg(attname)\n"
    4493             :                              "       FROM\n"
    4494             :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4495             :                              "         pg_catalog.pg_attribute\n"
    4496             :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4497             :                              "  ELSE NULL END) prattrs "
    4498             :                              "FROM pg_catalog.pg_publication_rel pr");
    4499             :     else
    4500           0 :         appendPQExpBufferStr(query,
    4501             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4502             :                              "NULL AS prrelqual, NULL AS prattrs "
    4503             :                              "FROM pg_catalog.pg_publication_rel");
    4504         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4505             : 
    4506         304 :     ntups = PQntuples(res);
    4507             : 
    4508         304 :     i_tableoid = PQfnumber(res, "tableoid");
    4509         304 :     i_oid = PQfnumber(res, "oid");
    4510         304 :     i_prpubid = PQfnumber(res, "prpubid");
    4511         304 :     i_prrelid = PQfnumber(res, "prrelid");
    4512         304 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4513         304 :     i_prattrs = PQfnumber(res, "prattrs");
    4514             : 
    4515             :     /* this allocation may be more than we need */
    4516         304 :     pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4517         304 :     j = 0;
    4518             : 
    4519         906 :     for (i = 0; i < ntups; i++)
    4520             :     {
    4521         602 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4522         602 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4523             :         PublicationInfo *pubinfo;
    4524             :         TableInfo  *tbinfo;
    4525             : 
    4526             :         /*
    4527             :          * Ignore any entries for which we aren't interested in either the
    4528             :          * publication or the rel.
    4529             :          */
    4530         602 :         pubinfo = findPublicationByOid(prpubid);
    4531         602 :         if (pubinfo == NULL)
    4532           0 :             continue;
    4533         602 :         tbinfo = findTableByOid(prrelid);
    4534         602 :         if (tbinfo == NULL)
    4535           0 :             continue;
    4536             : 
    4537             :         /*
    4538             :          * Ignore publication membership of tables whose definitions are not
    4539             :          * to be dumped.
    4540             :          */
    4541         602 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    4542          92 :             continue;
    4543             : 
    4544             :         /* OK, make a DumpableObject for this relationship */
    4545         510 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4546         510 :         pubrinfo[j].dobj.catId.tableoid =
    4547         510 :             atooid(PQgetvalue(res, i, i_tableoid));
    4548         510 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4549         510 :         AssignDumpId(&pubrinfo[j].dobj);
    4550         510 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4551         510 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4552         510 :         pubrinfo[j].publication = pubinfo;
    4553         510 :         pubrinfo[j].pubtable = tbinfo;
    4554         510 :         if (PQgetisnull(res, i, i_prrelqual))
    4555         292 :             pubrinfo[j].pubrelqual = NULL;
    4556             :         else
    4557         218 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4558             : 
    4559         510 :         if (!PQgetisnull(res, i, i_prattrs))
    4560             :         {
    4561             :             char      **attnames;
    4562             :             int         nattnames;
    4563             :             PQExpBuffer attribs;
    4564             : 
    4565         144 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4566             :                               &attnames, &nattnames))
    4567           0 :                 pg_fatal("could not parse %s array", "prattrs");
    4568         144 :             attribs = createPQExpBuffer();
    4569         432 :             for (int k = 0; k < nattnames; k++)
    4570             :             {
    4571         288 :                 if (k > 0)
    4572         144 :                     appendPQExpBufferStr(attribs, ", ");
    4573             : 
    4574         288 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4575             :             }
    4576         144 :             pubrinfo[j].pubrattrs = attribs->data;
    4577             :         }
    4578             :         else
    4579         366 :             pubrinfo[j].pubrattrs = NULL;
    4580             : 
    4581             :         /* Decide whether we want to dump it */
    4582         510 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4583             : 
    4584         510 :         j++;
    4585             :     }
    4586             : 
    4587         304 :     PQclear(res);
    4588         304 :     destroyPQExpBuffer(query);
    4589             : }
    4590             : 
    4591             : /*
    4592             :  * dumpPublicationNamespace
    4593             :  *    dump the definition of the given publication schema mapping.
    4594             :  */
    4595             : static void
    4596         138 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4597             : {
    4598         138 :     DumpOptions *dopt = fout->dopt;
    4599         138 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4600         138 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4601             :     PQExpBuffer query;
    4602             :     char       *tag;
    4603             : 
    4604             :     /* Do nothing in data-only dump */
    4605         138 :     if (dopt->dataOnly)
    4606          12 :         return;
    4607             : 
    4608         126 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4609             : 
    4610         126 :     query = createPQExpBuffer();
    4611             : 
    4612         126 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4613         126 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4614             : 
    4615             :     /*
    4616             :      * There is no point in creating drop query as the drop is done by schema
    4617             :      * drop.
    4618             :      */
    4619         126 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4620         126 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4621         126 :                      ARCHIVE_OPTS(.tag = tag,
    4622             :                                   .namespace = schemainfo->dobj.name,
    4623             :                                   .owner = pubinfo->rolname,
    4624             :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4625             :                                   .section = SECTION_POST_DATA,
    4626             :                                   .createStmt = query->data));
    4627             : 
    4628             :     /* These objects can't currently have comments or seclabels */
    4629             : 
    4630         126 :     free(tag);
    4631         126 :     destroyPQExpBuffer(query);
    4632             : }
    4633             : 
    4634             : /*
    4635             :  * dumpPublicationTable
    4636             :  *    dump the definition of the given publication table mapping
    4637             :  */
    4638             : static void
    4639         470 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    4640             : {
    4641         470 :     DumpOptions *dopt = fout->dopt;
    4642         470 :     PublicationInfo *pubinfo = pubrinfo->publication;
    4643         470 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    4644             :     PQExpBuffer query;
    4645             :     char       *tag;
    4646             : 
    4647             :     /* Do nothing in data-only dump */
    4648         470 :     if (dopt->dataOnly)
    4649          42 :         return;
    4650             : 
    4651         428 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    4652             : 
    4653         428 :     query = createPQExpBuffer();
    4654             : 
    4655         428 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    4656         428 :                       fmtId(pubinfo->dobj.name));
    4657         428 :     appendPQExpBuffer(query, " %s",
    4658         428 :                       fmtQualifiedDumpable(tbinfo));
    4659             : 
    4660         428 :     if (pubrinfo->pubrattrs)
    4661         124 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    4662             : 
    4663         428 :     if (pubrinfo->pubrelqual)
    4664             :     {
    4665             :         /*
    4666             :          * It's necessary to add parentheses around the expression because
    4667             :          * pg_get_expr won't supply the parentheses for things like WHERE
    4668             :          * TRUE.
    4669             :          */
    4670         184 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    4671             :     }
    4672         428 :     appendPQExpBufferStr(query, ";\n");
    4673             : 
    4674             :     /*
    4675             :      * There is no point in creating a drop query as the drop is done by table
    4676             :      * drop.  (If you think to change this, see also _printTocEntry().)
    4677             :      * Although this object doesn't really have ownership as such, set the
    4678             :      * owner field anyway to ensure that the command is run by the correct
    4679             :      * role at restore time.
    4680             :      */
    4681         428 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4682         428 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    4683         428 :                      ARCHIVE_OPTS(.tag = tag,
    4684             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    4685             :                                   .owner = pubinfo->rolname,
    4686             :                                   .description = "PUBLICATION TABLE",
    4687             :                                   .section = SECTION_POST_DATA,
    4688             :                                   .createStmt = query->data));
    4689             : 
    4690             :     /* These objects can't currently have comments or seclabels */
    4691             : 
    4692         428 :     free(tag);
    4693         428 :     destroyPQExpBuffer(query);
    4694             : }
    4695             : 
    4696             : /*
    4697             :  * Is the currently connected user a superuser?
    4698             :  */
    4699             : static bool
    4700         304 : is_superuser(Archive *fout)
    4701             : {
    4702         304 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    4703             :     const char *val;
    4704             : 
    4705         304 :     val = PQparameterStatus(AH->connection, "is_superuser");
    4706             : 
    4707         304 :     if (val && strcmp(val, "on") == 0)
    4708         298 :         return true;
    4709             : 
    4710           6 :     return false;
    4711             : }
    4712             : 
    4713             : /*
    4714             :  * getSubscriptions
    4715             :  *    get information about subscriptions
    4716             :  */
    4717             : void
    4718         304 : getSubscriptions(Archive *fout)
    4719             : {
    4720         304 :     DumpOptions *dopt = fout->dopt;
    4721             :     PQExpBuffer query;
    4722             :     PGresult   *res;
    4723             :     SubscriptionInfo *subinfo;
    4724             :     int         i_tableoid;
    4725             :     int         i_oid;
    4726             :     int         i_subname;
    4727             :     int         i_subowner;
    4728             :     int         i_subbinary;
    4729             :     int         i_substream;
    4730             :     int         i_subtwophasestate;
    4731             :     int         i_subdisableonerr;
    4732             :     int         i_subpasswordrequired;
    4733             :     int         i_subrunasowner;
    4734             :     int         i_subconninfo;
    4735             :     int         i_subslotname;
    4736             :     int         i_subsynccommit;
    4737             :     int         i_subpublications;
    4738             :     int         i_suborigin;
    4739             :     int         i_suboriginremotelsn;
    4740             :     int         i_subenabled;
    4741             :     int         i_subfailover;
    4742             :     int         i,
    4743             :                 ntups;
    4744             : 
    4745         304 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    4746           0 :         return;
    4747             : 
    4748         304 :     if (!is_superuser(fout))
    4749             :     {
    4750             :         int         n;
    4751             : 
    4752           6 :         res = ExecuteSqlQuery(fout,
    4753             :                               "SELECT count(*) FROM pg_subscription "
    4754             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    4755             :                               "                 WHERE datname = current_database())",
    4756             :                               PGRES_TUPLES_OK);
    4757           6 :         n = atoi(PQgetvalue(res, 0, 0));
    4758           6 :         if (n > 0)
    4759           4 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    4760           6 :         PQclear(res);
    4761           6 :         return;
    4762             :     }
    4763             : 
    4764         298 :     query = createPQExpBuffer();
    4765             : 
    4766             :     /* Get the subscriptions in current database. */
    4767         298 :     appendPQExpBufferStr(query,
    4768             :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    4769             :                          " s.subowner,\n"
    4770             :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    4771             :                          " s.subpublications,\n");
    4772             : 
    4773         298 :     if (fout->remoteVersion >= 140000)
    4774         298 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    4775             :     else
    4776           0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    4777             : 
    4778         298 :     if (fout->remoteVersion >= 140000)
    4779         298 :         appendPQExpBufferStr(query, " s.substream,\n");
    4780             :     else
    4781           0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    4782             : 
    4783         298 :     if (fout->remoteVersion >= 150000)
    4784         298 :         appendPQExpBufferStr(query,
    4785             :                              " s.subtwophasestate,\n"
    4786             :                              " s.subdisableonerr,\n");
    4787             :     else
    4788           0 :         appendPQExpBuffer(query,
    4789             :                           " '%c' AS subtwophasestate,\n"
    4790             :                           " false AS subdisableonerr,\n",
    4791             :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    4792             : 
    4793         298 :     if (fout->remoteVersion >= 160000)
    4794         298 :         appendPQExpBufferStr(query,
    4795             :                              " s.subpasswordrequired,\n"
    4796             :                              " s.subrunasowner,\n"
    4797             :                              " s.suborigin,\n");
    4798             :     else
    4799           0 :         appendPQExpBuffer(query,
    4800             :                           " 't' AS subpasswordrequired,\n"
    4801             :                           " 't' AS subrunasowner,\n"
    4802             :                           " '%s' AS suborigin,\n",
    4803             :                           LOGICALREP_ORIGIN_ANY);
    4804             : 
    4805         298 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    4806          28 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    4807             :                              " s.subenabled,\n");
    4808             :     else
    4809         270 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    4810             :                              " false AS subenabled,\n");
    4811             : 
    4812         298 :     if (fout->remoteVersion >= 170000)
    4813         298 :         appendPQExpBufferStr(query,
    4814             :                              " s.subfailover\n");
    4815             :     else
    4816           0 :         appendPQExpBuffer(query,
    4817             :                           " false AS subfailover\n");
    4818             : 
    4819         298 :     appendPQExpBufferStr(query,
    4820             :                          "FROM pg_subscription s\n");
    4821             : 
    4822         298 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    4823          28 :         appendPQExpBufferStr(query,
    4824             :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    4825             :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    4826             : 
    4827         298 :     appendPQExpBufferStr(query,
    4828             :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    4829             :                          "                   WHERE datname = current_database())");
    4830             : 
    4831         298 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4832             : 
    4833         298 :     ntups = PQntuples(res);
    4834             : 
    4835             :     /*
    4836             :      * Get subscription fields. We don't include subskiplsn in the dump as
    4837             :      * after restoring the dump this value may no longer be relevant.
    4838             :      */
    4839         298 :     i_tableoid = PQfnumber(res, "tableoid");
    4840         298 :     i_oid = PQfnumber(res, "oid");
    4841         298 :     i_subname = PQfnumber(res, "subname");
    4842         298 :     i_subowner = PQfnumber(res, "subowner");
    4843         298 :     i_subbinary = PQfnumber(res, "subbinary");
    4844         298 :     i_substream = PQfnumber(res, "substream");
    4845         298 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    4846         298 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    4847         298 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    4848         298 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    4849         298 :     i_subconninfo = PQfnumber(res, "subconninfo");
    4850         298 :     i_subslotname = PQfnumber(res, "subslotname");
    4851         298 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    4852         298 :     i_subpublications = PQfnumber(res, "subpublications");
    4853         298 :     i_suborigin = PQfnumber(res, "suborigin");
    4854         298 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    4855         298 :     i_subenabled = PQfnumber(res, "subenabled");
    4856         298 :     i_subfailover = PQfnumber(res, "subfailover");
    4857             : 
    4858         298 :     subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    4859             : 
    4860         548 :     for (i = 0; i < ntups; i++)
    4861             :     {
    4862         250 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    4863         250 :         subinfo[i].dobj.catId.tableoid =
    4864         250 :             atooid(PQgetvalue(res, i, i_tableoid));
    4865         250 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4866         250 :         AssignDumpId(&subinfo[i].dobj);
    4867         250 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    4868         250 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    4869             : 
    4870         500 :         subinfo[i].subbinary =
    4871         250 :             pg_strdup(PQgetvalue(res, i, i_subbinary));
    4872         500 :         subinfo[i].substream =
    4873         250 :             pg_strdup(PQgetvalue(res, i, i_substream));
    4874         500 :         subinfo[i].subtwophasestate =
    4875         250 :             pg_strdup(PQgetvalue(res, i, i_subtwophasestate));
    4876         500 :         subinfo[i].subdisableonerr =
    4877         250 :             pg_strdup(PQgetvalue(res, i, i_subdisableonerr));
    4878         500 :         subinfo[i].subpasswordrequired =
    4879         250 :             pg_strdup(PQgetvalue(res, i, i_subpasswordrequired));
    4880         500 :         subinfo[i].subrunasowner =
    4881         250 :             pg_strdup(PQgetvalue(res, i, i_subrunasowner));
    4882         500 :         subinfo[i].subconninfo =
    4883         250 :             pg_strdup(PQgetvalue(res, i, i_subconninfo));
    4884         250 :         if (PQgetisnull(res, i, i_subslotname))
    4885           0 :             subinfo[i].subslotname = NULL;
    4886             :         else
    4887         250 :             subinfo[i].subslotname =
    4888         250 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    4889         500 :         subinfo[i].subsynccommit =
    4890         250 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    4891         500 :         subinfo[i].subpublications =
    4892         250 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    4893         250 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    4894         250 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    4895         248 :             subinfo[i].suboriginremotelsn = NULL;
    4896             :         else
    4897           2 :             subinfo[i].suboriginremotelsn =
    4898           2 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    4899         500 :         subinfo[i].subenabled =
    4900         250 :             pg_strdup(PQgetvalue(res, i, i_subenabled));
    4901         500 :         subinfo[i].subfailover =
    4902         250 :             pg_strdup(PQgetvalue(res, i, i_subfailover));
    4903             : 
    4904             :         /* Decide whether we want to dump it */
    4905         250 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    4906             :     }
    4907         298 :     PQclear(res);
    4908             : 
    4909         298 :     destroyPQExpBuffer(query);
    4910             : }
    4911             : 
    4912             : /*
    4913             :  * getSubscriptionTables
    4914             :  *    Get information about subscription membership for dumpable tables. This
    4915             :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    4916             :  */
    4917             : void
    4918         304 : getSubscriptionTables(Archive *fout)
    4919             : {
    4920         304 :     DumpOptions *dopt = fout->dopt;
    4921         304 :     SubscriptionInfo *subinfo = NULL;
    4922             :     SubRelInfo *subrinfo;
    4923             :     PGresult   *res;
    4924             :     int         i_srsubid;
    4925             :     int         i_srrelid;
    4926             :     int         i_srsubstate;
    4927             :     int         i_srsublsn;
    4928             :     int         ntups;
    4929         304 :     Oid         last_srsubid = InvalidOid;
    4930             : 
    4931         304 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    4932          28 :         fout->remoteVersion < 170000)
    4933         276 :         return;
    4934             : 
    4935          28 :     res = ExecuteSqlQuery(fout,
    4936             :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    4937             :                           "FROM pg_catalog.pg_subscription_rel "
    4938             :                           "ORDER BY srsubid",
    4939             :                           PGRES_TUPLES_OK);
    4940          28 :     ntups = PQntuples(res);
    4941          28 :     if (ntups == 0)
    4942          26 :         goto cleanup;
    4943             : 
    4944             :     /* Get pg_subscription_rel attributes */
    4945           2 :     i_srsubid = PQfnumber(res, "srsubid");
    4946           2 :     i_srrelid = PQfnumber(res, "srrelid");
    4947           2 :     i_srsubstate = PQfnumber(res, "srsubstate");
    4948           2 :     i_srsublsn = PQfnumber(res, "srsublsn");
    4949             : 
    4950           2 :     subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
    4951           6 :     for (int i = 0; i < ntups; i++)
    4952             :     {
    4953           4 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    4954           4 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    4955             :         TableInfo  *tblinfo;
    4956             : 
    4957             :         /*
    4958             :          * If we switched to a new subscription, check if the subscription
    4959             :          * exists.
    4960             :          */
    4961           4 :         if (cur_srsubid != last_srsubid)
    4962             :         {
    4963           4 :             subinfo = findSubscriptionByOid(cur_srsubid);
    4964           4 :             if (subinfo == NULL)
    4965           0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    4966             : 
    4967           4 :             last_srsubid = cur_srsubid;
    4968             :         }
    4969             : 
    4970           4 :         tblinfo = findTableByOid(relid);
    4971           4 :         if (tblinfo == NULL)
    4972           0 :             pg_fatal("failed sanity check, table with OID %u not found",
    4973             :                      relid);
    4974             : 
    4975             :         /* OK, make a DumpableObject for this relationship */
    4976           4 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    4977           4 :         subrinfo[i].dobj.catId.tableoid = relid;
    4978           4 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    4979           4 :         AssignDumpId(&subrinfo[i].dobj);
    4980           4 :         subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
    4981           4 :         subrinfo[i].tblinfo = tblinfo;
    4982           4 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    4983           4 :         if (PQgetisnull(res, i, i_srsublsn))
    4984           2 :             subrinfo[i].srsublsn = NULL;
    4985             :         else
    4986           2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    4987             : 
    4988           4 :         subrinfo[i].subinfo = subinfo;
    4989             : 
    4990             :         /* Decide whether we want to dump it */
    4991           4 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    4992             :     }
    4993             : 
    4994           2 : cleanup:
    4995          28 :     PQclear(res);
    4996             : }
    4997             : 
    4998             : /*
    4999             :  * dumpSubscriptionTable
    5000             :  *    Dump the definition of the given subscription table mapping. This will be
    5001             :  *    used only in binary-upgrade mode for PG17 or later versions.
    5002             :  */
    5003             : static void
    5004           4 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5005             : {
    5006           4 :     DumpOptions *dopt = fout->dopt;
    5007           4 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5008             :     PQExpBuffer query;
    5009             :     char       *tag;
    5010             : 
    5011             :     /* Do nothing in data-only dump */
    5012           4 :     if (dopt->dataOnly)
    5013           0 :         return;
    5014             : 
    5015             :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5016             : 
    5017           4 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
    5018             : 
    5019           4 :     query = createPQExpBuffer();
    5020             : 
    5021           4 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5022             :     {
    5023             :         /*
    5024             :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5025             :          * to pg_subscription_rel table. This will be used only in
    5026             :          * binary-upgrade mode.
    5027             :          */
    5028           4 :         appendPQExpBufferStr(query,
    5029             :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5030           4 :         appendPQExpBufferStr(query,
    5031             :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5032           4 :         appendStringLiteralAH(query, subrinfo->dobj.name, fout);
    5033           4 :         appendPQExpBuffer(query,
    5034             :                           ", %u, '%c'",
    5035           4 :                           subrinfo->tblinfo->dobj.catId.oid,
    5036           4 :                           subrinfo->srsubstate);
    5037             : 
    5038           4 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5039           2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5040             :         else
    5041           2 :             appendPQExpBuffer(query, ", NULL");
    5042             : 
    5043           4 :         appendPQExpBufferStr(query, ");\n");
    5044             :     }
    5045             : 
    5046             :     /*
    5047             :      * There is no point in creating a drop query as the drop is done by table
    5048             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5049             :      * Although this object doesn't really have ownership as such, set the
    5050             :      * owner field anyway to ensure that the command is run by the correct
    5051             :      * role at restore time.
    5052             :      */
    5053           4 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5054           4 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5055           4 :                      ARCHIVE_OPTS(.tag = tag,
    5056             :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5057             :                                   .owner = subinfo->rolname,
    5058             :                                   .description = "SUBSCRIPTION TABLE",
    5059             :                                   .section = SECTION_POST_DATA,
    5060             :                                   .createStmt = query->data));
    5061             : 
    5062             :     /* These objects can't currently have comments or seclabels */
    5063             : 
    5064           4 :     free(tag);
    5065           4 :     destroyPQExpBuffer(query);
    5066             : }
    5067             : 
    5068             : /*
    5069             :  * dumpSubscription
    5070             :  *    dump the definition of the given subscription
    5071             :  */
    5072             : static void
    5073         214 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5074             : {
    5075         214 :     DumpOptions *dopt = fout->dopt;
    5076             :     PQExpBuffer delq;
    5077             :     PQExpBuffer query;
    5078             :     PQExpBuffer publications;
    5079             :     char       *qsubname;
    5080         214 :     char      **pubnames = NULL;
    5081         214 :     int         npubnames = 0;
    5082             :     int         i;
    5083         214 :     char        two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};
    5084             : 
    5085             :     /* Do nothing in data-only dump */
    5086         214 :     if (dopt->dataOnly)
    5087          18 :         return;
    5088             : 
    5089         196 :     delq = createPQExpBuffer();
    5090         196 :     query = createPQExpBuffer();
    5091             : 
    5092         196 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5093             : 
    5094         196 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5095             :                       qsubname);
    5096             : 
    5097         196 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5098             :                       qsubname);
    5099         196 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5100             : 
    5101             :     /* Build list of quoted publications and append them to query. */
    5102         196 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5103           0 :         pg_fatal("could not parse %s array", "subpublications");
    5104             : 
    5105         196 :     publications = createPQExpBuffer();
    5106         392 :     for (i = 0; i < npubnames; i++)
    5107             :     {
    5108         196 :         if (i > 0)
    5109           0 :             appendPQExpBufferStr(publications, ", ");
    5110             : 
    5111         196 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5112             :     }
    5113             : 
    5114         196 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5115         196 :     if (subinfo->subslotname)
    5116         196 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5117             :     else
    5118           0 :         appendPQExpBufferStr(query, "NONE");
    5119             : 
    5120         196 :     if (strcmp(subinfo->subbinary, "t") == 0)
    5121           0 :         appendPQExpBufferStr(query, ", binary = true");
    5122             : 
    5123         196 :     if (strcmp(subinfo->substream, "t") == 0)
    5124           0 :         appendPQExpBufferStr(query, ", streaming = on");
    5125         196 :     else if (strcmp(subinfo->substream, "p") == 0)
    5126           0 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5127             : 
    5128         196 :     if (strcmp(subinfo->subtwophasestate, two_phase_disabled) != 0)
    5129           0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5130             : 
    5131         196 :     if (strcmp(subinfo->subdisableonerr, "t") == 0)
    5132           0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5133             : 
    5134         196 :     if (strcmp(subinfo->subpasswordrequired, "t") != 0)
    5135           0 :         appendPQExpBuffer(query, ", password_required = false");
    5136             : 
    5137         196 :     if (strcmp(subinfo->subrunasowner, "t") == 0)
    5138           0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5139             : 
    5140         196 :     if (strcmp(subinfo->subfailover, "t") == 0)
    5141           2 :         appendPQExpBufferStr(query, ", failover = true");
    5142             : 
    5143         196 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5144           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5145             : 
    5146         196 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5147          64 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5148             : 
    5149         196 :     appendPQExpBufferStr(query, ");\n");
    5150             : 
    5151             :     /*
    5152             :      * In binary-upgrade mode, we allow the replication to continue after the
    5153             :      * upgrade.
    5154             :      */
    5155         196 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5156             :     {
    5157          10 :         if (subinfo->suboriginremotelsn)
    5158             :         {
    5159             :             /*
    5160             :              * Preserve the remote_lsn for the subscriber's replication
    5161             :              * origin. This value is required to start the replication from
    5162             :              * the position before the upgrade. This value will be stale if
    5163             :              * the publisher gets upgraded before the subscriber node.
    5164             :              * However, this shouldn't be a problem as the upgrade of the
    5165             :              * publisher ensures that all the transactions were replicated
    5166             :              * before upgrading it.
    5167             :              */
    5168           2 :             appendPQExpBufferStr(query,
    5169             :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5170           2 :             appendPQExpBufferStr(query,
    5171             :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5172           2 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5173           2 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5174             :         }
    5175             : 
    5176          10 :         if (strcmp(subinfo->subenabled, "t") == 0)
    5177             :         {
    5178             :             /*
    5179             :              * Enable the subscription to allow the replication to continue
    5180             :              * after the upgrade.
    5181             :              */
    5182           2 :             appendPQExpBufferStr(query,
    5183             :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5184           2 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5185             :         }
    5186             :     }
    5187             : 
    5188         196 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5189         196 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5190         196 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5191             :                                   .owner = subinfo->rolname,
    5192             :                                   .description = "SUBSCRIPTION",
    5193             :                                   .section = SECTION_POST_DATA,
    5194             :                                   .createStmt = query->data,
    5195             :                                   .dropStmt = delq->data));
    5196             : 
    5197         196 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5198          64 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5199             :                     NULL, subinfo->rolname,
    5200             :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5201             : 
    5202         196 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5203           0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5204             :                      NULL, subinfo->rolname,
    5205             :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5206             : 
    5207         196 :     destroyPQExpBuffer(publications);
    5208         196 :     free(pubnames);
    5209             : 
    5210         196 :     destroyPQExpBuffer(delq);
    5211         196 :     destroyPQExpBuffer(query);
    5212         196 :     free(qsubname);
    5213             : }
    5214             : 
    5215             : /*
    5216             :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5217             :  * the object needs.
    5218             :  */
    5219             : static void
    5220        9212 : append_depends_on_extension(Archive *fout,
    5221             :                             PQExpBuffer create,
    5222             :                             const DumpableObject *dobj,
    5223             :                             const char *catalog,
    5224             :                             const char *keyword,
    5225             :                             const char *objname)
    5226             : {
    5227        9212 :     if (dobj->depends_on_ext)
    5228             :     {
    5229             :         char       *nm;
    5230             :         PGresult   *res;
    5231             :         PQExpBuffer query;
    5232             :         int         ntups;
    5233             :         int         i_extname;
    5234             :         int         i;
    5235             : 
    5236             :         /* dodge fmtId() non-reentrancy */
    5237          84 :         nm = pg_strdup(objname);
    5238             : 
    5239          84 :         query = createPQExpBuffer();
    5240          84 :         appendPQExpBuffer(query,
    5241             :                           "SELECT e.extname "
    5242             :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5243             :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5244             :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5245             :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5246             :                           catalog,
    5247             :                           dobj->catId.oid);
    5248          84 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5249          84 :         ntups = PQntuples(res);
    5250          84 :         i_extname = PQfnumber(res, "extname");
    5251         168 :         for (i = 0; i < ntups; i++)
    5252             :         {
    5253          84 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5254             :                               keyword, nm,
    5255          84 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5256             :         }
    5257             : 
    5258          84 :         PQclear(res);
    5259          84 :         destroyPQExpBuffer(query);
    5260          84 :         pg_free(nm);
    5261             :     }
    5262        9212 : }
    5263             : 
    5264             : static Oid
    5265           0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5266             : {
    5267             :     /*
    5268             :      * If the old version didn't assign an array type, but the new version
    5269             :      * does, we must select an unused type OID to assign.  This currently only
    5270             :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5271             :      *
    5272             :      * Note: local state here is kind of ugly, but we must have some, since we
    5273             :      * mustn't choose the same unused OID more than once.
    5274             :      */
    5275             :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5276             :     PGresult   *res;
    5277             :     bool        is_dup;
    5278             : 
    5279             :     do
    5280             :     {
    5281           0 :         ++next_possible_free_oid;
    5282           0 :         printfPQExpBuffer(upgrade_query,
    5283             :                           "SELECT EXISTS(SELECT 1 "
    5284             :                           "FROM pg_catalog.pg_type "
    5285             :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5286             :                           next_possible_free_oid);
    5287           0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5288           0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5289           0 :         PQclear(res);
    5290           0 :     } while (is_dup);
    5291             : 
    5292           0 :     return next_possible_free_oid;
    5293             : }
    5294             : 
    5295             : static void
    5296        1644 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5297             :                                          PQExpBuffer upgrade_buffer,
    5298             :                                          Oid pg_type_oid,
    5299             :                                          bool force_array_type,
    5300             :                                          bool include_multirange_type)
    5301             : {
    5302        1644 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5303             :     PGresult   *res;
    5304             :     Oid         pg_type_array_oid;
    5305             :     Oid         pg_type_multirange_oid;
    5306             :     Oid         pg_type_multirange_array_oid;
    5307             : 
    5308        1644 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5309        1644 :     appendPQExpBuffer(upgrade_buffer,
    5310             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5311             :                       pg_type_oid);
    5312             : 
    5313        1644 :     appendPQExpBuffer(upgrade_query,
    5314             :                       "SELECT typarray "
    5315             :                       "FROM pg_catalog.pg_type "
    5316             :                       "WHERE oid = '%u'::pg_catalog.oid;",
    5317             :                       pg_type_oid);
    5318             : 
    5319        1644 :     res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5320             : 
    5321        1644 :     pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5322             : 
    5323        1644 :     PQclear(res);
    5324             : 
    5325        1644 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5326           0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5327             : 
    5328        1644 :     if (OidIsValid(pg_type_array_oid))
    5329             :     {
    5330        1640 :         appendPQExpBufferStr(upgrade_buffer,
    5331             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5332        1640 :         appendPQExpBuffer(upgrade_buffer,
    5333             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5334             :                           pg_type_array_oid);
    5335             :     }
    5336             : 
    5337             :     /*
    5338             :      * Pre-set the multirange type oid and its own array type oid.
    5339             :      */
    5340        1644 :     if (include_multirange_type)
    5341             :     {
    5342          12 :         if (fout->remoteVersion >= 140000)
    5343             :         {
    5344          12 :             printfPQExpBuffer(upgrade_query,
    5345             :                               "SELECT t.oid, t.typarray "
    5346             :                               "FROM pg_catalog.pg_type t "
    5347             :                               "JOIN pg_catalog.pg_range r "
    5348             :                               "ON t.oid = r.rngmultitypid "
    5349             :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5350             :                               pg_type_oid);
    5351             : 
    5352          12 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5353             : 
    5354          12 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5355          12 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5356             : 
    5357          12 :             PQclear(res);
    5358             :         }
    5359             :         else
    5360             :         {
    5361           0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5362           0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5363             :         }
    5364             : 
    5365          12 :         appendPQExpBufferStr(upgrade_buffer,
    5366             :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5367          12 :         appendPQExpBuffer(upgrade_buffer,
    5368             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5369             :                           pg_type_multirange_oid);
    5370          12 :         appendPQExpBufferStr(upgrade_buffer,
    5371             :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5372          12 :         appendPQExpBuffer(upgrade_buffer,
    5373             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5374             :                           pg_type_multirange_array_oid);
    5375             :     }
    5376             : 
    5377        1644 :     destroyPQExpBuffer(upgrade_query);
    5378        1644 : }
    5379             : 
    5380             : static void
    5381        1510 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5382             :                                     PQExpBuffer upgrade_buffer,
    5383             :                                     const TableInfo *tbinfo)
    5384             : {
    5385        1510 :     Oid         pg_type_oid = tbinfo->reltype;
    5386             : 
    5387        1510 :     if (OidIsValid(pg_type_oid))
    5388        1510 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5389             :                                                  pg_type_oid, false, false);
    5390        1510 : }
    5391             : 
    5392             : static void
    5393        2206 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5394             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
    5395             :                                  bool is_index)
    5396             : {
    5397        2206 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5398             :     PGresult   *upgrade_res;
    5399             :     RelFileNumber relfilenumber;
    5400             :     Oid         toast_oid;
    5401             :     RelFileNumber toast_relfilenumber;
    5402             :     char        relkind;
    5403             :     Oid         toast_index_oid;
    5404             :     RelFileNumber toast_index_relfilenumber;
    5405             : 
    5406             :     /*
    5407             :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5408             :      * toast table and toast table's index if any.
    5409             :      *
    5410             :      * One complexity is that the current table definition might not require
    5411             :      * the creation of a TOAST table, but the old database might have a TOAST
    5412             :      * table that was created earlier, before some wide columns were dropped.
    5413             :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5414             :      * by the new backend, so we can copy the files during binary upgrade
    5415             :      * without worrying about this case.
    5416             :      */
    5417        2206 :     appendPQExpBuffer(upgrade_query,
    5418             :                       "SELECT c.relkind, c.relfilenode, c.reltoastrelid, ct.relfilenode AS toast_relfilenode, i.indexrelid, cti.relfilenode AS toast_index_relfilenode "
    5419             :                       "FROM pg_catalog.pg_class c LEFT JOIN "
    5420             :                       "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5421             :                       "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5422             :                       "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5423             :                       "WHERE c.oid = '%u'::pg_catalog.oid;",
    5424             :                       pg_class_oid);
    5425             : 
    5426        2206 :     upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5427             : 
    5428        2206 :     relkind = *PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "relkind"));
    5429             : 
    5430        2206 :     relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
    5431             :                                       PQfnumber(upgrade_res, "relfilenode")));
    5432        2206 :     toast_oid = atooid(PQgetvalue(upgrade_res, 0,
    5433             :                                   PQfnumber(upgrade_res, "reltoastrelid")));
    5434        2206 :     toast_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
    5435             :                                             PQfnumber(upgrade_res, "toast_relfilenode")));
    5436        2206 :     toast_index_oid = atooid(PQgetvalue(upgrade_res, 0,
    5437             :                                         PQfnumber(upgrade_res, "indexrelid")));
    5438        2206 :     toast_index_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
    5439             :                                                   PQfnumber(upgrade_res, "toast_index_relfilenode")));
    5440             : 
    5441        2206 :     appendPQExpBufferStr(upgrade_buffer,
    5442             :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5443             : 
    5444        2206 :     if (!is_index)
    5445             :     {
    5446        1656 :         appendPQExpBuffer(upgrade_buffer,
    5447             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5448             :                           pg_class_oid);
    5449             : 
    5450             :         /*
    5451             :          * Not every relation has storage. Also, in a pre-v12 database,
    5452             :          * partitioned tables have a relfilenumber, which should not be
    5453             :          * preserved when upgrading.
    5454             :          */
    5455        1656 :         if (RelFileNumberIsValid(relfilenumber) && relkind != RELKIND_PARTITIONED_TABLE)
    5456        1356 :             appendPQExpBuffer(upgrade_buffer,
    5457             :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5458             :                               relfilenumber);
    5459             : 
    5460             :         /*
    5461             :          * In a pre-v12 database, partitioned tables might be marked as having
    5462             :          * toast tables, but we should ignore them if so.
    5463             :          */
    5464        1656 :         if (OidIsValid(toast_oid) &&
    5465             :             relkind != RELKIND_PARTITIONED_TABLE)
    5466             :         {
    5467         550 :             appendPQExpBuffer(upgrade_buffer,
    5468             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5469             :                               toast_oid);
    5470         550 :             appendPQExpBuffer(upgrade_buffer,
    5471             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5472             :                               toast_relfilenumber);
    5473             : 
    5474             :             /* every toast table has an index */
    5475         550 :             appendPQExpBuffer(upgrade_buffer,
    5476             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5477             :                               toast_index_oid);
    5478         550 :             appendPQExpBuffer(upgrade_buffer,
    5479             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5480             :                               toast_index_relfilenumber);
    5481             :         }
    5482             : 
    5483        1656 :         PQclear(upgrade_res);
    5484             :     }
    5485             :     else
    5486             :     {
    5487             :         /* Preserve the OID and relfilenumber of the index */
    5488         550 :         appendPQExpBuffer(upgrade_buffer,
    5489             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5490             :                           pg_class_oid);
    5491         550 :         appendPQExpBuffer(upgrade_buffer,
    5492             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5493             :                           relfilenumber);
    5494             :     }
    5495             : 
    5496        2206 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5497             : 
    5498        2206 :     destroyPQExpBuffer(upgrade_query);
    5499        2206 : }
    5500             : 
    5501             : /*
    5502             :  * If the DumpableObject is a member of an extension, add a suitable
    5503             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5504             :  *
    5505             :  * For somewhat historical reasons, objname should already be quoted,
    5506             :  * but not objnamespace (if any).
    5507             :  */
    5508             : static void
    5509        2620 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5510             :                                 const DumpableObject *dobj,
    5511             :                                 const char *objtype,
    5512             :                                 const char *objname,
    5513             :                                 const char *objnamespace)
    5514             : {
    5515        2620 :     DumpableObject *extobj = NULL;
    5516             :     int         i;
    5517             : 
    5518        2620 :     if (!dobj->ext_member)
    5519        2588 :         return;
    5520             : 
    5521             :     /*
    5522             :      * Find the parent extension.  We could avoid this search if we wanted to
    5523             :      * add a link field to DumpableObject, but the space costs of that would
    5524             :      * be considerable.  We assume that member objects could only have a
    5525             :      * direct dependency on their own extension, not any others.
    5526             :      */
    5527          32 :     for (i = 0; i < dobj->nDeps; i++)
    5528             :     {
    5529          32 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    5530          32 :         if (extobj && extobj->objType == DO_EXTENSION)
    5531          32 :             break;
    5532           0 :         extobj = NULL;
    5533             :     }
    5534          32 :     if (extobj == NULL)
    5535           0 :         pg_fatal("could not find parent extension for %s %s",
    5536             :                  objtype, objname);
    5537             : 
    5538          32 :     appendPQExpBufferStr(upgrade_buffer,
    5539             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    5540          32 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5541          32 :                       fmtId(extobj->name),
    5542             :                       objtype);
    5543          32 :     if (objnamespace && *objnamespace)
    5544          26 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5545          32 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5546             : }
    5547             : 
    5548             : /*
    5549             :  * getNamespaces:
    5550             :  *    read all namespaces in the system catalogs and return them in the
    5551             :  * NamespaceInfo* structure
    5552             :  *
    5553             :  *  numNamespaces is set to the number of namespaces read in
    5554             :  */
    5555             : NamespaceInfo *
    5556         306 : getNamespaces(Archive *fout, int *numNamespaces)
    5557             : {
    5558             :     PGresult   *res;
    5559             :     int         ntups;
    5560             :     int         i;
    5561             :     PQExpBuffer query;
    5562             :     NamespaceInfo *nsinfo;
    5563             :     int         i_tableoid;
    5564             :     int         i_oid;
    5565             :     int         i_nspname;
    5566             :     int         i_nspowner;
    5567             :     int         i_nspacl;
    5568             :     int         i_acldefault;
    5569             : 
    5570         306 :     query = createPQExpBuffer();
    5571             : 
    5572             :     /*
    5573             :      * we fetch all namespaces including system ones, so that every object we
    5574             :      * read in can be linked to a containing namespace.
    5575             :      */
    5576         306 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    5577             :                          "n.nspowner, "
    5578             :                          "n.nspacl, "
    5579             :                          "acldefault('n', n.nspowner) AS acldefault "
    5580             :                          "FROM pg_namespace n");
    5581             : 
    5582         306 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5583             : 
    5584         306 :     ntups = PQntuples(res);
    5585             : 
    5586         306 :     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    5587             : 
    5588         306 :     i_tableoid = PQfnumber(res, "tableoid");
    5589         306 :     i_oid = PQfnumber(res, "oid");
    5590         306 :     i_nspname = PQfnumber(res, "nspname");
    5591         306 :     i_nspowner = PQfnumber(res, "nspowner");
    5592         306 :     i_nspacl = PQfnumber(res, "nspacl");
    5593         306 :     i_acldefault = PQfnumber(res, "acldefault");
    5594             : 
    5595        2582 :     for (i = 0; i < ntups; i++)
    5596             :     {
    5597             :         const char *nspowner;
    5598             : 
    5599        2276 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    5600        2276 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5601        2276 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5602        2276 :         AssignDumpId(&nsinfo[i].dobj);
    5603        2276 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    5604        2276 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    5605        2276 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5606        2276 :         nsinfo[i].dacl.privtype = 0;
    5607        2276 :         nsinfo[i].dacl.initprivs = NULL;
    5608        2276 :         nspowner = PQgetvalue(res, i, i_nspowner);
    5609        2276 :         nsinfo[i].nspowner = atooid(nspowner);
    5610        2276 :         nsinfo[i].rolname = getRoleName(nspowner);
    5611             : 
    5612             :         /* Decide whether to dump this namespace */
    5613        2276 :         selectDumpableNamespace(&nsinfo[i], fout);
    5614             : 
    5615             :         /* Mark whether namespace has an ACL */
    5616        2276 :         if (!PQgetisnull(res, i, i_nspacl))
    5617        1006 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5618             : 
    5619             :         /*
    5620             :          * We ignore any pg_init_privs.initprivs entry for the public schema
    5621             :          * and assume a predetermined default, for several reasons.  First,
    5622             :          * dropping and recreating the schema removes its pg_init_privs entry,
    5623             :          * but an empty destination database starts with this ACL nonetheless.
    5624             :          * Second, we support dump/reload of public schema ownership changes.
    5625             :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    5626             :          * initprivs continues to reflect the initial owner.  Hence,
    5627             :          * synthesize the value that nspacl will have after the restore's
    5628             :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    5629             :          * match the source's ACL, even if the latter was an initdb-default
    5630             :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    5631             :          * system object ACLs that the DBA had not customized.  We've made the
    5632             :          * public schema depart from that, because changing its ACL so easily
    5633             :          * breaks applications.
    5634             :          */
    5635        2276 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    5636             :         {
    5637         298 :             PQExpBuffer aclarray = createPQExpBuffer();
    5638         298 :             PQExpBuffer aclitem = createPQExpBuffer();
    5639             : 
    5640             :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    5641         298 :             appendPQExpBufferChar(aclarray, '{');
    5642         298 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5643         298 :             appendPQExpBufferStr(aclitem, "=UC/");
    5644         298 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5645         298 :             appendPGArray(aclarray, aclitem->data);
    5646         298 :             resetPQExpBuffer(aclitem);
    5647         298 :             appendPQExpBufferStr(aclitem, "=U/");
    5648         298 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5649         298 :             appendPGArray(aclarray, aclitem->data);
    5650         298 :             appendPQExpBufferChar(aclarray, '}');
    5651             : 
    5652         298 :             nsinfo[i].dacl.privtype = 'i';
    5653         298 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    5654         298 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5655             : 
    5656         298 :             destroyPQExpBuffer(aclarray);
    5657         298 :             destroyPQExpBuffer(aclitem);
    5658             :         }
    5659             :     }
    5660             : 
    5661         306 :     PQclear(res);
    5662         306 :     destroyPQExpBuffer(query);
    5663             : 
    5664         306 :     *numNamespaces = ntups;
    5665             : 
    5666         306 :     return nsinfo;
    5667             : }
    5668             : 
    5669             : /*
    5670             :  * findNamespace:
    5671             :  *      given a namespace OID, look up the info read by getNamespaces
    5672             :  */
    5673             : static NamespaceInfo *
    5674      940808 : findNamespace(Oid nsoid)
    5675             : {
    5676             :     NamespaceInfo *nsinfo;
    5677             : 
    5678      940808 :     nsinfo = findNamespaceByOid(nsoid);
    5679      940808 :     if (nsinfo == NULL)
    5680           0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    5681      940808 :     return nsinfo;
    5682             : }
    5683             : 
    5684             : /*
    5685             :  * getExtensions:
    5686             :  *    read all extensions in the system catalogs and return them in the
    5687             :  * ExtensionInfo* structure
    5688             :  *
    5689             :  *  numExtensions is set to the number of extensions read in
    5690             :  */
    5691             : ExtensionInfo *
    5692         306 : getExtensions(Archive *fout, int *numExtensions)
    5693             : {
    5694         306 :     DumpOptions *dopt = fout->dopt;
    5695             :     PGresult   *res;
    5696             :     int         ntups;
    5697             :     int         i;
    5698             :     PQExpBuffer query;
    5699             :     ExtensionInfo *extinfo;
    5700             :     int         i_tableoid;
    5701             :     int         i_oid;
    5702             :     int         i_extname;
    5703             :     int         i_nspname;
    5704             :     int         i_extrelocatable;
    5705             :     int         i_extversion;
    5706             :     int         i_extconfig;
    5707             :     int         i_extcondition;
    5708             : 
    5709         306 :     query = createPQExpBuffer();
    5710             : 
    5711         306 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    5712             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    5713             :                          "FROM pg_extension x "
    5714             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    5715             : 
    5716         306 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5717             : 
    5718         306 :     ntups = PQntuples(res);
    5719             : 
    5720         306 :     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    5721             : 
    5722         306 :     i_tableoid = PQfnumber(res, "tableoid");
    5723         306 :     i_oid = PQfnumber(res, "oid");
    5724         306 :     i_extname = PQfnumber(res, "extname");
    5725         306 :     i_nspname = PQfnumber(res, "nspname");
    5726         306 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    5727         306 :     i_extversion = PQfnumber(res, "extversion");
    5728         306 :     i_extconfig = PQfnumber(res, "extconfig");
    5729         306 :     i_extcondition = PQfnumber(res, "extcondition");
    5730             : 
    5731         662 :     for (i = 0; i < ntups; i++)
    5732             :     {
    5733         356 :         extinfo[i].dobj.objType = DO_EXTENSION;
    5734         356 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5735         356 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5736         356 :         AssignDumpId(&extinfo[i].dobj);
    5737         356 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    5738         356 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    5739         356 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    5740         356 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    5741         356 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    5742         356 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    5743             : 
    5744             :         /* Decide whether we want to dump it */
    5745         356 :         selectDumpableExtension(&(extinfo[i]), dopt);
    5746             :     }
    5747             : 
    5748         306 :     PQclear(res);
    5749         306 :     destroyPQExpBuffer(query);
    5750             : 
    5751         306 :     *numExtensions = ntups;
    5752             : 
    5753         306 :     return extinfo;
    5754             : }
    5755             : 
    5756             : /*
    5757             :  * getTypes:
    5758             :  *    read all types in the system catalogs and return them in the
    5759             :  * TypeInfo* structure
    5760             :  *
    5761             :  *  numTypes is set to the number of types read in
    5762             :  *
    5763             :  * NB: this must run after getFuncs() because we assume we can do
    5764             :  * findFuncByOid().
    5765             :  */
    5766             : TypeInfo *
    5767         304 : getTypes(Archive *fout, int *numTypes)
    5768             : {
    5769             :     PGresult   *res;
    5770             :     int         ntups;
    5771             :     int         i;
    5772         304 :     PQExpBuffer query = createPQExpBuffer();
    5773             :     TypeInfo   *tyinfo;
    5774             :     ShellTypeInfo *stinfo;
    5775             :     int         i_tableoid;
    5776             :     int         i_oid;
    5777             :     int         i_typname;
    5778             :     int         i_typnamespace;
    5779             :     int         i_typacl;
    5780             :     int         i_acldefault;
    5781             :     int         i_typowner;
    5782             :     int         i_typelem;
    5783             :     int         i_typrelid;
    5784             :     int         i_typrelkind;
    5785             :     int         i_typtype;
    5786             :     int         i_typisdefined;
    5787             :     int         i_isarray;
    5788             : 
    5789             :     /*
    5790             :      * we include even the built-in types because those may be used as array
    5791             :      * elements by user-defined types
    5792             :      *
    5793             :      * we filter out the built-in types when we dump out the types
    5794             :      *
    5795             :      * same approach for undefined (shell) types and array types
    5796             :      *
    5797             :      * Note: as of 8.3 we can reliably detect whether a type is an
    5798             :      * auto-generated array type by checking the element type's typarray.
    5799             :      * (Before that the test is capable of generating false positives.) We
    5800             :      * still check for name beginning with '_', though, so as to avoid the
    5801             :      * cost of the subselect probe for all standard types.  This would have to
    5802             :      * be revisited if the backend ever allows renaming of array types.
    5803             :      */
    5804         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    5805             :                          "typnamespace, typacl, "
    5806             :                          "acldefault('T', typowner) AS acldefault, "
    5807             :                          "typowner, "
    5808             :                          "typelem, typrelid, "
    5809             :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    5810             :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    5811             :                          "typtype, typisdefined, "
    5812             :                          "typname[0] = '_' AND typelem != 0 AND "
    5813             :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    5814             :                          "FROM pg_type");
    5815             : 
    5816         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5817             : 
    5818         304 :     ntups = PQntuples(res);
    5819             : 
    5820         304 :     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    5821             : 
    5822         304 :     i_tableoid = PQfnumber(res, "tableoid");
    5823         304 :     i_oid = PQfnumber(res, "oid");
    5824         304 :     i_typname = PQfnumber(res, "typname");
    5825         304 :     i_typnamespace = PQfnumber(res, "typnamespace");
    5826         304 :     i_typacl = PQfnumber(res, "typacl");
    5827         304 :     i_acldefault = PQfnumber(res, "acldefault");
    5828         304 :     i_typowner = PQfnumber(res, "typowner");
    5829         304 :     i_typelem = PQfnumber(res, "typelem");
    5830         304 :     i_typrelid = PQfnumber(res, "typrelid");
    5831         304 :     i_typrelkind = PQfnumber(res, "typrelkind");
    5832         304 :     i_typtype = PQfnumber(res, "typtype");
    5833         304 :     i_typisdefined = PQfnumber(res, "typisdefined");
    5834         304 :     i_isarray = PQfnumber(res, "isarray");
    5835             : 
    5836      213500 :     for (i = 0; i < ntups; i++)
    5837             :     {
    5838      213196 :         tyinfo[i].dobj.objType = DO_TYPE;
    5839      213196 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5840      213196 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5841      213196 :         AssignDumpId(&tyinfo[i].dobj);
    5842      213196 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    5843      426392 :         tyinfo[i].dobj.namespace =
    5844      213196 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    5845      213196 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    5846      213196 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5847      213196 :         tyinfo[i].dacl.privtype = 0;
    5848      213196 :         tyinfo[i].dacl.initprivs = NULL;
    5849      213196 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    5850      213196 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    5851      213196 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    5852      213196 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    5853      213196 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    5854      213196 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    5855      213196 :         tyinfo[i].shellType = NULL;
    5856             : 
    5857      213196 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    5858      213100 :             tyinfo[i].isDefined = true;
    5859             :         else
    5860          96 :             tyinfo[i].isDefined = false;
    5861             : 
    5862      213196 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    5863      102142 :             tyinfo[i].isArray = true;
    5864             :         else
    5865      111054 :             tyinfo[i].isArray = false;
    5866             : 
    5867      213196 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    5868        2036 :             tyinfo[i].isMultirange = true;
    5869             :         else
    5870      211160 :             tyinfo[i].isMultirange = false;
    5871             : 
    5872             :         /* Decide whether we want to dump it */
    5873      213196 :         selectDumpableType(&tyinfo[i], fout);
    5874             : 
    5875             :         /* Mark whether type has an ACL */
    5876      213196 :         if (!PQgetisnull(res, i, i_typacl))
    5877         394 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5878             : 
    5879             :         /*
    5880             :          * If it's a domain, fetch info about its constraints, if any
    5881             :          */
    5882      213196 :         tyinfo[i].nDomChecks = 0;
    5883      213196 :         tyinfo[i].domChecks = NULL;
    5884      213196 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    5885       24314 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    5886         262 :             getDomainConstraints(fout, &(tyinfo[i]));
    5887             : 
    5888             :         /*
    5889             :          * If it's a base type, make a DumpableObject representing a shell
    5890             :          * definition of the type.  We will need to dump that ahead of the I/O
    5891             :          * functions for the type.  Similarly, range types need a shell
    5892             :          * definition in case they have a canonicalize function.
    5893             :          *
    5894             :          * Note: the shell type doesn't have a catId.  You might think it
    5895             :          * should copy the base type's catId, but then it might capture the
    5896             :          * pg_depend entries for the type, which we don't want.
    5897             :          */
    5898      213196 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    5899       24314 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    5900       11956 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    5901             :         {
    5902       12554 :             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    5903       12554 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    5904       12554 :             stinfo->dobj.catId = nilCatalogId;
    5905       12554 :             AssignDumpId(&stinfo->dobj);
    5906       12554 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    5907       12554 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    5908       12554 :             stinfo->baseType = &(tyinfo[i]);
    5909       12554 :             tyinfo[i].shellType = stinfo;
    5910             : 
    5911             :             /*
    5912             :              * Initially mark the shell type as not to be dumped.  We'll only
    5913             :              * dump it if the I/O or canonicalize functions need to be dumped;
    5914             :              * this is taken care of while sorting dependencies.
    5915             :              */
    5916       12554 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    5917             :         }
    5918             :     }
    5919             : 
    5920         304 :     *numTypes = ntups;
    5921             : 
    5922         304 :     PQclear(res);
    5923             : 
    5924         304 :     destroyPQExpBuffer(query);
    5925             : 
    5926         304 :     return tyinfo;
    5927             : }
    5928             : 
    5929             : /*
    5930             :  * getOperators:
    5931             :  *    read all operators in the system catalogs and return them in the
    5932             :  * OprInfo* structure
    5933             :  *
    5934             :  *  numOprs is set to the number of operators read in
    5935             :  */
    5936             : OprInfo *
    5937         304 : getOperators(Archive *fout, int *numOprs)
    5938             : {
    5939             :     PGresult   *res;
    5940             :     int         ntups;
    5941             :     int         i;
    5942         304 :     PQExpBuffer query = createPQExpBuffer();
    5943             :     OprInfo    *oprinfo;
    5944             :     int         i_tableoid;
    5945             :     int         i_oid;
    5946             :     int         i_oprname;
    5947             :     int         i_oprnamespace;
    5948             :     int         i_oprowner;
    5949             :     int         i_oprkind;
    5950             :     int         i_oprcode;
    5951             : 
    5952             :     /*
    5953             :      * find all operators, including builtin operators; we filter out
    5954             :      * system-defined operators at dump-out time.
    5955             :      */
    5956             : 
    5957         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    5958             :                          "oprnamespace, "
    5959             :                          "oprowner, "
    5960             :                          "oprkind, "
    5961             :                          "oprcode::oid AS oprcode "
    5962             :                          "FROM pg_operator");
    5963             : 
    5964         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5965             : 
    5966         304 :     ntups = PQntuples(res);
    5967         304 :     *numOprs = ntups;
    5968             : 
    5969         304 :     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    5970             : 
    5971         304 :     i_tableoid = PQfnumber(res, "tableoid");
    5972         304 :     i_oid = PQfnumber(res, "oid");
    5973         304 :     i_oprname = PQfnumber(res, "oprname");
    5974         304 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    5975         304 :     i_oprowner = PQfnumber(res, "oprowner");
    5976         304 :     i_oprkind = PQfnumber(res, "oprkind");
    5977         304 :     i_oprcode = PQfnumber(res, "oprcode");
    5978             : 
    5979      243424 :     for (i = 0; i < ntups; i++)
    5980             :     {
    5981      243120 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    5982      243120 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5983      243120 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5984      243120 :         AssignDumpId(&oprinfo[i].dobj);
    5985      243120 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    5986      486240 :         oprinfo[i].dobj.namespace =
    5987      243120 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    5988      243120 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    5989      243120 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    5990      243120 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    5991             : 
    5992             :         /* Decide whether we want to dump it */
    5993      243120 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    5994             :     }
    5995             : 
    5996         304 :     PQclear(res);
    5997             : 
    5998         304 :     destroyPQExpBuffer(query);
    5999             : 
    6000         304 :     return oprinfo;
    6001             : }
    6002             : 
    6003             : /*
    6004             :  * getCollations:
    6005             :  *    read all collations in the system catalogs and return them in the
    6006             :  * CollInfo* structure
    6007             :  *
    6008             :  *  numCollations is set to the number of collations read in
    6009             :  */
    6010             : CollInfo *
    6011         304 : getCollations(Archive *fout, int *numCollations)
    6012             : {
    6013             :     PGresult   *res;
    6014             :     int         ntups;
    6015             :     int         i;
    6016             :     PQExpBuffer query;
    6017             :     CollInfo   *collinfo;
    6018             :     int         i_tableoid;
    6019             :     int         i_oid;
    6020             :     int         i_collname;
    6021             :     int         i_collnamespace;
    6022             :     int         i_collowner;
    6023             : 
    6024         304 :     query = createPQExpBuffer();
    6025             : 
    6026             :     /*
    6027             :      * find all collations, including builtin collations; we filter out
    6028             :      * system-defined collations at dump-out time.
    6029             :      */
    6030             : 
    6031         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6032             :                          "collnamespace, "
    6033             :                          "collowner "
    6034             :                          "FROM pg_collation");
    6035             : 
    6036         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6037             : 
    6038         304 :     ntups = PQntuples(res);
    6039         304 :     *numCollations = ntups;
    6040             : 
    6041         304 :     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    6042             : 
    6043         304 :     i_tableoid = PQfnumber(res, "tableoid");
    6044         304 :     i_oid = PQfnumber(res, "oid");
    6045         304 :     i_collname = PQfnumber(res, "collname");
    6046         304 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6047         304 :     i_collowner = PQfnumber(res, "collowner");
    6048             : 
    6049      241264 :     for (i = 0; i < ntups; i++)
    6050             :     {
    6051      240960 :         collinfo[i].dobj.objType = DO_COLLATION;
    6052      240960 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6053      240960 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6054      240960 :         AssignDumpId(&collinfo[i].dobj);
    6055      240960 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6056      481920 :         collinfo[i].dobj.namespace =
    6057      240960 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6058      240960 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6059             : 
    6060             :         /* Decide whether we want to dump it */
    6061      240960 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6062             :     }
    6063             : 
    6064         304 :     PQclear(res);
    6065             : 
    6066         304 :     destroyPQExpBuffer(query);
    6067             : 
    6068         304 :     return collinfo;
    6069             : }
    6070             : 
    6071             : /*
    6072             :  * getConversions:
    6073             :  *    read all conversions in the system catalogs and return them in the
    6074             :  * ConvInfo* structure
    6075             :  *
    6076             :  *  numConversions is set to the number of conversions read in
    6077             :  */
    6078             : ConvInfo *
    6079         304 : getConversions(Archive *fout, int *numConversions)
    6080             : {
    6081             :     PGresult   *res;
    6082             :     int         ntups;
    6083             :     int         i;
    6084             :     PQExpBuffer query;
    6085             :     ConvInfo   *convinfo;
    6086             :     int         i_tableoid;
    6087             :     int         i_oid;
    6088             :     int         i_conname;
    6089             :     int         i_connamespace;
    6090             :     int         i_conowner;
    6091             : 
    6092         304 :     query = createPQExpBuffer();
    6093             : 
    6094             :     /*
    6095             :      * find all conversions, including builtin conversions; we filter out
    6096             :      * system-defined conversions at dump-out time.
    6097             :      */
    6098             : 
    6099         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6100             :                          "connamespace, "
    6101             :                          "conowner "
    6102             :                          "FROM pg_conversion");
    6103             : 
    6104         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6105             : 
    6106         304 :     ntups = PQntuples(res);
    6107         304 :     *numConversions = ntups;
    6108             : 
    6109         304 :     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    6110             : 
    6111         304 :     i_tableoid = PQfnumber(res, "tableoid");
    6112         304 :     i_oid = PQfnumber(res, "oid");
    6113         304 :     i_conname = PQfnumber(res, "conname");
    6114         304 :     i_connamespace = PQfnumber(res, "connamespace");
    6115         304 :     i_conowner = PQfnumber(res, "conowner");
    6116             : 
    6117       39302 :     for (i = 0; i < ntups; i++)
    6118             :     {
    6119       38998 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6120       38998 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6121       38998 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6122       38998 :         AssignDumpId(&convinfo[i].dobj);
    6123       38998 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6124       77996 :         convinfo[i].dobj.namespace =
    6125       38998 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6126       38998 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6127             : 
    6128             :         /* Decide whether we want to dump it */
    6129       38998 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6130             :     }
    6131             : 
    6132         304 :     PQclear(res);
    6133             : 
    6134         304 :     destroyPQExpBuffer(query);
    6135             : 
    6136         304 :     return convinfo;
    6137             : }
    6138             : 
    6139             : /*
    6140             :  * getAccessMethods:
    6141             :  *    read all user-defined access methods in the system catalogs and return
    6142             :  *    them in the AccessMethodInfo* structure
    6143             :  *
    6144             :  *  numAccessMethods is set to the number of access methods read in
    6145             :  */
    6146             : AccessMethodInfo *
    6147         304 : getAccessMethods(Archive *fout, int *numAccessMethods)
    6148             : {
    6149             :     PGresult   *res;
    6150             :     int         ntups;
    6151             :     int         i;
    6152             :     PQExpBuffer query;
    6153             :     AccessMethodInfo *aminfo;
    6154             :     int         i_tableoid;
    6155             :     int         i_oid;
    6156             :     int         i_amname;
    6157             :     int         i_amhandler;
    6158             :     int         i_amtype;
    6159             : 
    6160             :     /* Before 9.6, there are no user-defined access methods */
    6161         304 :     if (fout->remoteVersion < 90600)
    6162             :     {
    6163           0 :         *numAccessMethods = 0;
    6164           0 :         return NULL;
    6165             :     }
    6166             : 
    6167         304 :     query = createPQExpBuffer();
    6168             : 
    6169             :     /* Select all access methods from pg_am table */
    6170         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
    6171             :                          "amhandler::pg_catalog.regproc AS amhandler "
    6172             :                          "FROM pg_am");
    6173             : 
    6174         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6175             : 
    6176         304 :     ntups = PQntuples(res);
    6177         304 :     *numAccessMethods = ntups;
    6178             : 
    6179         304 :     aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    6180             : 
    6181         304 :     i_tableoid = PQfnumber(res, "tableoid");
    6182         304 :     i_oid = PQfnumber(res, "oid");
    6183         304 :     i_amname = PQfnumber(res, "amname");
    6184         304 :     i_amhandler = PQfnumber(res, "amhandler");
    6185         304 :     i_amtype = PQfnumber(res, "amtype");
    6186             : 
    6187        2664 :     for (i = 0; i < ntups; i++)
    6188             :     {
    6189        2360 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6190        2360 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6191        2360 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6192        2360 :         AssignDumpId(&aminfo[i].dobj);
    6193        2360 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6194        2360 :         aminfo[i].dobj.namespace = NULL;
    6195        2360 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6196        2360 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6197             : 
    6198             :         /* Decide whether we want to dump it */
    6199        2360 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6200             :     }
    6201             : 
    6202         304 :     PQclear(res);
    6203             : 
    6204         304 :     destroyPQExpBuffer(query);
    6205             : 
    6206         304 :     return aminfo;
    6207             : }
    6208             : 
    6209             : 
    6210             : /*
    6211             :  * getOpclasses:
    6212             :  *    read all opclasses in the system catalogs and return them in the
    6213             :  * OpclassInfo* structure
    6214             :  *
    6215             :  *  numOpclasses is set to the number of opclasses read in
    6216             :  */
    6217             : OpclassInfo *
    6218         304 : getOpclasses(Archive *fout, int *numOpclasses)
    6219             : {
    6220             :     PGresult   *res;
    6221             :     int         ntups;
    6222             :     int         i;
    6223         304 :     PQExpBuffer query = createPQExpBuffer();
    6224             :     OpclassInfo *opcinfo;
    6225             :     int         i_tableoid;
    6226             :     int         i_oid;
    6227             :     int         i_opcname;
    6228             :     int         i_opcnamespace;
    6229             :     int         i_opcowner;
    6230             : 
    6231             :     /*
    6232             :      * find all opclasses, including builtin opclasses; we filter out
    6233             :      * system-defined opclasses at dump-out time.
    6234             :      */
    6235             : 
    6236         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
    6237             :                          "opcnamespace, "
    6238             :                          "opcowner "
    6239             :                          "FROM pg_opclass");
    6240             : 
    6241         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6242             : 
    6243         304 :     ntups = PQntuples(res);
    6244         304 :     *numOpclasses = ntups;
    6245             : 
    6246         304 :     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    6247             : 
    6248         304 :     i_tableoid = PQfnumber(res, "tableoid");
    6249         304 :     i_oid = PQfnumber(res, "oid");
    6250         304 :     i_opcname = PQfnumber(res, "opcname");
    6251         304 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6252         304 :     i_opcowner = PQfnumber(res, "opcowner");
    6253             : 
    6254       54400 :     for (i = 0; i < ntups; i++)
    6255             :     {
    6256       54096 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6257       54096 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6258       54096 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6259       54096 :         AssignDumpId(&opcinfo[i].dobj);
    6260       54096 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6261      108192 :         opcinfo[i].dobj.namespace =
    6262       54096 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6263       54096 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6264             : 
    6265             :         /* Decide whether we want to dump it */
    6266       54096 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6267             :     }
    6268             : 
    6269         304 :     PQclear(res);
    6270             : 
    6271         304 :     destroyPQExpBuffer(query);
    6272             : 
    6273         304 :     return opcinfo;
    6274             : }
    6275             : 
    6276             : /*
    6277             :  * getOpfamilies:
    6278             :  *    read all opfamilies in the system catalogs and return them in the
    6279             :  * OpfamilyInfo* structure
    6280             :  *
    6281             :  *  numOpfamilies is set to the number of opfamilies read in
    6282             :  */
    6283             : OpfamilyInfo *
    6284         304 : getOpfamilies(Archive *fout, int *numOpfamilies)
    6285             : {
    6286             :     PGresult   *res;
    6287             :     int         ntups;
    6288             :     int         i;
    6289             :     PQExpBuffer query;
    6290             :     OpfamilyInfo *opfinfo;
    6291             :     int         i_tableoid;
    6292             :     int         i_oid;
    6293             :     int         i_opfname;
    6294             :     int         i_opfnamespace;
    6295             :     int         i_opfowner;
    6296             : 
    6297         304 :     query = createPQExpBuffer();
    6298             : 
    6299             :     /*
    6300             :      * find all opfamilies, including builtin opfamilies; we filter out
    6301             :      * system-defined opfamilies at dump-out time.
    6302             :      */
    6303             : 
    6304         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
    6305             :                          "opfnamespace, "
    6306             :                          "opfowner "
    6307             :                          "FROM pg_opfamily");
    6308             : 
    6309         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6310             : 
    6311         304 :     ntups = PQntuples(res);
    6312         304 :     *numOpfamilies = ntups;
    6313             : 
    6314         304 :     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    6315             : 
    6316         304 :     i_tableoid = PQfnumber(res, "tableoid");
    6317         304 :     i_oid = PQfnumber(res, "oid");
    6318         304 :     i_opfname = PQfnumber(res, "opfname");
    6319         304 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6320         304 :     i_opfowner = PQfnumber(res, "opfowner");
    6321             : 
    6322       44930 :     for (i = 0; i < ntups; i++)
    6323             :     {
    6324       44626 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6325       44626 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6326       44626 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6327       44626 :         AssignDumpId(&opfinfo[i].dobj);
    6328       44626 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6329       89252 :         opfinfo[i].dobj.namespace =
    6330       44626 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6331       44626 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6332             : 
    6333             :         /* Decide whether we want to dump it */
    6334       44626 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6335             :     }
    6336             : 
    6337         304 :     PQclear(res);
    6338             : 
    6339         304 :     destroyPQExpBuffer(query);
    6340             : 
    6341         304 :     return opfinfo;
    6342             : }
    6343             : 
    6344             : /*
    6345             :  * getAggregates:
    6346             :  *    read all the user-defined aggregates in the system catalogs and
    6347             :  * return them in the AggInfo* structure
    6348             :  *
    6349             :  * numAggs is set to the number of aggregates read in
    6350             :  */
    6351             : AggInfo *
    6352         304 : getAggregates(Archive *fout, int *numAggs)
    6353             : {
    6354         304 :     DumpOptions *dopt = fout->dopt;
    6355             :     PGresult   *res;
    6356             :     int         ntups;
    6357             :     int         i;
    6358         304 :     PQExpBuffer query = createPQExpBuffer();
    6359             :     AggInfo    *agginfo;
    6360             :     int         i_tableoid;
    6361             :     int         i_oid;
    6362             :     int         i_aggname;
    6363             :     int         i_aggnamespace;
    6364             :     int         i_pronargs;
    6365             :     int         i_proargtypes;
    6366             :     int         i_proowner;
    6367             :     int         i_aggacl;
    6368             :     int         i_acldefault;
    6369             : 
    6370             :     /*
    6371             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6372             :      * rationale behind the filtering logic.
    6373             :      */
    6374         304 :     if (fout->remoteVersion >= 90600)
    6375             :     {
    6376             :         const char *agg_check;
    6377             : 
    6378         608 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6379         304 :                      : "p.proisagg");
    6380             : 
    6381         304 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6382             :                           "p.proname AS aggname, "
    6383             :                           "p.pronamespace AS aggnamespace, "
    6384             :                           "p.pronargs, p.proargtypes, "
    6385             :                           "p.proowner, "
    6386             :                           "p.proacl AS aggacl, "
    6387             :                           "acldefault('f', p.proowner) AS acldefault "
    6388             :                           "FROM pg_proc p "
    6389             :                           "LEFT JOIN pg_init_privs pip ON "
    6390             :                           "(p.oid = pip.objoid "
    6391             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6392             :                           "AND pip.objsubid = 0) "
    6393             :                           "WHERE %s AND ("
    6394             :                           "p.pronamespace != "
    6395             :                           "(SELECT oid FROM pg_namespace "
    6396             :                           "WHERE nspname = 'pg_catalog') OR "
    6397             :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6398             :                           agg_check);
    6399         304 :         if (dopt->binary_upgrade)
    6400          28 :             appendPQExpBufferStr(query,
    6401             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6402             :                                  "classid = 'pg_proc'::regclass AND "
    6403             :                                  "objid = p.oid AND "
    6404             :                                  "refclassid = 'pg_extension'::regclass AND "
    6405             :                                  "deptype = 'e')");
    6406         304 :         appendPQExpBufferChar(query, ')');
    6407             :     }
    6408             :     else
    6409             :     {
    6410           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6411             :                              "pronamespace AS aggnamespace, "
    6412             :                              "pronargs, proargtypes, "
    6413             :                              "proowner, "
    6414             :                              "proacl AS aggacl, "
    6415             :                              "acldefault('f', proowner) AS acldefault "
    6416             :                              "FROM pg_proc p "
    6417             :                              "WHERE proisagg AND ("
    6418             :                              "pronamespace != "
    6419             :                              "(SELECT oid FROM pg_namespace "
    6420             :                              "WHERE nspname = 'pg_catalog')");
    6421           0 :         if (dopt->binary_upgrade)
    6422           0 :             appendPQExpBufferStr(query,
    6423             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6424             :                                  "classid = 'pg_proc'::regclass AND "
    6425             :                                  "objid = p.oid AND "
    6426             :                                  "refclassid = 'pg_extension'::regclass AND "
    6427             :                                  "deptype = 'e')");
    6428           0 :         appendPQExpBufferChar(query, ')');
    6429             :     }
    6430             : 
    6431         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6432             : 
    6433         304 :     ntups = PQntuples(res);
    6434         304 :     *numAggs = ntups;
    6435             : 
    6436         304 :     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    6437             : 
    6438         304 :     i_tableoid = PQfnumber(res, "tableoid");
    6439         304 :     i_oid = PQfnumber(res, "oid");
    6440         304 :     i_aggname = PQfnumber(res, "aggname");
    6441         304 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6442         304 :     i_pronargs = PQfnumber(res, "pronargs");
    6443         304 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6444         304 :     i_proowner = PQfnumber(res, "proowner");
    6445         304 :     i_aggacl = PQfnumber(res, "aggacl");
    6446         304 :     i_acldefault = PQfnumber(res, "acldefault");
    6447             : 
    6448         910 :     for (i = 0; i < ntups; i++)
    6449             :     {
    6450         606 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6451         606 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6452         606 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6453         606 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6454         606 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6455        1212 :         agginfo[i].aggfn.dobj.namespace =
    6456         606 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6457         606 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6458         606 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6459         606 :         agginfo[i].aggfn.dacl.privtype = 0;
    6460         606 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6461         606 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6462         606 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6463         606 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6464         606 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6465         606 :         if (agginfo[i].aggfn.nargs == 0)
    6466          80 :             agginfo[i].aggfn.argtypes = NULL;
    6467             :         else
    6468             :         {
    6469         526 :             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    6470         526 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6471         526 :                           agginfo[i].aggfn.argtypes,
    6472         526 :                           agginfo[i].aggfn.nargs);
    6473             :         }
    6474         606 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6475             : 
    6476             :         /* Decide whether we want to dump it */
    6477         606 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6478             : 
    6479             :         /* Mark whether aggregate has an ACL */
    6480         606 :         if (!PQgetisnull(res, i, i_aggacl))
    6481          50 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6482             :     }
    6483             : 
    6484         304 :     PQclear(res);
    6485             : 
    6486         304 :     destroyPQExpBuffer(query);
    6487             : 
    6488         304 :     return agginfo;
    6489             : }
    6490             : 
    6491             : /*
    6492             :  * getFuncs:
    6493             :  *    read all the user-defined functions in the system catalogs and
    6494             :  * return them in the FuncInfo* structure
    6495             :  *
    6496             :  * numFuncs is set to the number of functions read in
    6497             :  */
    6498             : FuncInfo *
    6499         304 : getFuncs(Archive *fout, int *numFuncs)
    6500             : {
    6501         304 :     DumpOptions *dopt = fout->dopt;
    6502             :     PGresult   *res;
    6503             :     int         ntups;
    6504             :     int         i;
    6505         304 :     PQExpBuffer query = createPQExpBuffer();
    6506             :     FuncInfo   *finfo;
    6507             :     int         i_tableoid;
    6508             :     int         i_oid;
    6509             :     int         i_proname;
    6510             :     int         i_pronamespace;
    6511             :     int         i_proowner;
    6512             :     int         i_prolang;
    6513             :     int         i_pronargs;
    6514             :     int         i_proargtypes;
    6515             :     int         i_prorettype;
    6516             :     int         i_proacl;
    6517             :     int         i_acldefault;
    6518             : 
    6519             :     /*
    6520             :      * Find all interesting functions.  This is a bit complicated:
    6521             :      *
    6522             :      * 1. Always exclude aggregates; those are handled elsewhere.
    6523             :      *
    6524             :      * 2. Always exclude functions that are internally dependent on something
    6525             :      * else, since presumably those will be created as a result of creating
    6526             :      * the something else.  This currently acts only to suppress constructor
    6527             :      * functions for range types.  Note this is OK only because the
    6528             :      * constructors don't have any dependencies the range type doesn't have;
    6529             :      * otherwise we might not get creation ordering correct.
    6530             :      *
    6531             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6532             :      * they're members of extensions and we are in binary-upgrade mode then
    6533             :      * include them, since we want to dump extension members individually in
    6534             :      * that mode.  Also, if they are used by casts or transforms then we need
    6535             :      * to gather the information about them, though they won't be dumped if
    6536             :      * they are built-in.  Also, in 9.6 and up, include functions in
    6537             :      * pg_catalog if they have an ACL different from what's shown in
    6538             :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6539             :      */
    6540         304 :     if (fout->remoteVersion >= 90600)
    6541             :     {
    6542             :         const char *not_agg_check;
    6543             : 
    6544         608 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6545         304 :                          : "NOT p.proisagg");
    6546             : 
    6547         304 :         appendPQExpBuffer(query,
    6548             :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6549             :                           "p.pronargs, p.proargtypes, p.prorettype, "
    6550             :                           "p.proacl, "
    6551             :                           "acldefault('f', p.proowner) AS acldefault, "
    6552             :                           "p.pronamespace, "
    6553             :                           "p.proowner "
    6554             :                           "FROM pg_proc p "
    6555             :                           "LEFT JOIN pg_init_privs pip ON "
    6556             :                           "(p.oid = pip.objoid "
    6557             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6558             :                           "AND pip.objsubid = 0) "
    6559             :                           "WHERE %s"
    6560             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6561             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6562             :                           "objid = p.oid AND deptype = 'i')"
    6563             :                           "\n  AND ("
    6564             :                           "\n  pronamespace != "
    6565             :                           "(SELECT oid FROM pg_namespace "
    6566             :                           "WHERE nspname = 'pg_catalog')"
    6567             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6568             :                           "\n  WHERE pg_cast.oid > %u "
    6569             :                           "\n  AND p.oid = pg_cast.castfunc)"
    6570             :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6571             :                           "\n  WHERE pg_transform.oid > %u AND "
    6572             :                           "\n  (p.oid = pg_transform.trffromsql"
    6573             :                           "\n  OR p.oid = pg_transform.trftosql))",
    6574             :                           not_agg_check,
    6575             :                           g_last_builtin_oid,
    6576             :                           g_last_builtin_oid);
    6577         304 :         if (dopt->binary_upgrade)
    6578          28 :             appendPQExpBufferStr(query,
    6579             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6580             :                                  "classid = 'pg_proc'::regclass AND "
    6581             :                                  "objid = p.oid AND "
    6582             :                                  "refclassid = 'pg_extension'::regclass AND "
    6583             :                                  "deptype = 'e')");
    6584         304 :         appendPQExpBufferStr(query,
    6585             :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    6586         304 :         appendPQExpBufferChar(query, ')');
    6587             :     }
    6588             :     else
    6589             :     {
    6590           0 :         appendPQExpBuffer(query,
    6591             :                           "SELECT tableoid, oid, proname, prolang, "
    6592             :                           "pronargs, proargtypes, prorettype, proacl, "
    6593             :                           "acldefault('f', proowner) AS acldefault, "
    6594             :                           "pronamespace, "
    6595             :                           "proowner "
    6596             :                           "FROM pg_proc p "
    6597             :                           "WHERE NOT proisagg"
    6598             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6599             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6600             :                           "objid = p.oid AND deptype = 'i')"
    6601             :                           "\n  AND ("
    6602             :                           "\n  pronamespace != "
    6603             :                           "(SELECT oid FROM pg_namespace "
    6604             :                           "WHERE nspname = 'pg_catalog')"
    6605             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6606             :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    6607             :                           "\n  AND p.oid = pg_cast.castfunc)",
    6608             :                           g_last_builtin_oid);
    6609             : 
    6610           0 :         if (fout->remoteVersion >= 90500)
    6611           0 :             appendPQExpBuffer(query,
    6612             :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6613             :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    6614             :                               "\n  AND (p.oid = pg_transform.trffromsql"
    6615             :                               "\n  OR p.oid = pg_transform.trftosql))",
    6616             :                               g_last_builtin_oid);
    6617             : 
    6618           0 :         if (dopt->binary_upgrade)
    6619           0 :             appendPQExpBufferStr(query,
    6620             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6621             :                                  "classid = 'pg_proc'::regclass AND "
    6622             :                                  "objid = p.oid AND "
    6623             :                                  "refclassid = 'pg_extension'::regclass AND "
    6624             :                                  "deptype = 'e')");
    6625           0 :         appendPQExpBufferChar(query, ')');
    6626             :     }
    6627             : 
    6628         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6629             : 
    6630         304 :     ntups = PQntuples(res);
    6631             : 
    6632         304 :     *numFuncs = ntups;
    6633             : 
    6634         304 :     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    6635             : 
    6636         304 :     i_tableoid = PQfnumber(res, "tableoid");
    6637         304 :     i_oid = PQfnumber(res, "oid");
    6638         304 :     i_proname = PQfnumber(res, "proname");
    6639         304 :     i_pronamespace = PQfnumber(res, "pronamespace");
    6640         304 :     i_proowner = PQfnumber(res, "proowner");
    6641         304 :     i_prolang = PQfnumber(res, "prolang");
    6642         304 :     i_pronargs = PQfnumber(res, "pronargs");
    6643         304 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6644         304 :     i_prorettype = PQfnumber(res, "prorettype");
    6645         304 :     i_proacl = PQfnumber(res, "proacl");
    6646         304 :     i_acldefault = PQfnumber(res, "acldefault");
    6647             : 
    6648        7686 :     for (i = 0; i < ntups; i++)
    6649             :     {
    6650        7382 :         finfo[i].dobj.objType = DO_FUNC;
    6651        7382 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6652        7382 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6653        7382 :         AssignDumpId(&finfo[i].dobj);
    6654        7382 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    6655       14764 :         finfo[i].dobj.namespace =
    6656        7382 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    6657        7382 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    6658        7382 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6659        7382 :         finfo[i].dacl.privtype = 0;
    6660        7382 :         finfo[i].dacl.initprivs = NULL;
    6661        7382 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6662        7382 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    6663        7382 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    6664        7382 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6665        7382 :         if (finfo[i].nargs == 0)
    6666        1618 :             finfo[i].argtypes = NULL;
    6667             :         else
    6668             :         {
    6669        5764 :             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    6670        5764 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6671        5764 :                           finfo[i].argtypes, finfo[i].nargs);
    6672             :         }
    6673        7382 :         finfo[i].postponed_def = false; /* might get set during sort */
    6674             : 
    6675             :         /* Decide whether we want to dump it */
    6676        7382 :         selectDumpableObject(&(finfo[i].dobj), fout);
    6677             : 
    6678             :         /* Mark whether function has an ACL */
    6679        7382 :         if (!PQgetisnull(res, i, i_proacl))
    6680         272 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6681             :     }
    6682             : 
    6683         304 :     PQclear(res);
    6684             : 
    6685         304 :     destroyPQExpBuffer(query);
    6686             : 
    6687         304 :     return finfo;
    6688             : }
    6689             : 
    6690             : /*
    6691             :  * getTables
    6692             :  *    read all the tables (no indexes) in the system catalogs,
    6693             :  *    and return them as an array of TableInfo structures
    6694             :  *
    6695             :  * *numTables is set to the number of tables read in
    6696             :  */
    6697             : TableInfo *
    6698         306 : getTables(Archive *fout, int *numTables)
    6699             : {
    6700         306 :     DumpOptions *dopt = fout->dopt;
    6701             :     PGresult   *res;
    6702             :     int         ntups;
    6703             :     int         i;
    6704         306 :     PQExpBuffer query = createPQExpBuffer();
    6705             :     TableInfo  *tblinfo;
    6706             :     int         i_reltableoid;
    6707             :     int         i_reloid;
    6708             :     int         i_relname;
    6709             :     int         i_relnamespace;
    6710             :     int         i_relkind;
    6711             :     int         i_reltype;
    6712             :     int         i_relowner;
    6713             :     int         i_relchecks;
    6714             :     int         i_relhasindex;
    6715             :     int         i_relhasrules;
    6716             :     int         i_relpages;
    6717             :     int         i_toastpages;
    6718             :     int         i_owning_tab;
    6719             :     int         i_owning_col;
    6720             :     int         i_reltablespace;
    6721             :     int         i_relhasoids;
    6722             :     int         i_relhastriggers;
    6723             :     int         i_relpersistence;
    6724             :     int         i_relispopulated;
    6725             :     int         i_relreplident;
    6726             :     int         i_relrowsec;
    6727             :     int         i_relforcerowsec;
    6728             :     int         i_relfrozenxid;
    6729             :     int         i_toastfrozenxid;
    6730             :     int         i_toastoid;
    6731             :     int         i_relminmxid;
    6732             :     int         i_toastminmxid;
    6733             :     int         i_reloptions;
    6734             :     int         i_checkoption;
    6735             :     int         i_toastreloptions;
    6736             :     int         i_reloftype;
    6737             :     int         i_foreignserver;
    6738             :     int         i_amname;
    6739             :     int         i_is_identity_sequence;
    6740             :     int         i_relacl;
    6741             :     int         i_acldefault;
    6742             :     int         i_ispartition;
    6743             : 
    6744             :     /*
    6745             :      * Find all the tables and table-like objects.
    6746             :      *
    6747             :      * We must fetch all tables in this phase because otherwise we cannot
    6748             :      * correctly identify inherited columns, owned sequences, etc.
    6749             :      *
    6750             :      * We include system catalogs, so that we can work if a user table is
    6751             :      * defined to inherit from a system catalog (pretty weird, but...)
    6752             :      *
    6753             :      * Note: in this phase we should collect only a minimal amount of
    6754             :      * information about each table, basically just enough to decide if it is
    6755             :      * interesting.  In particular, since we do not yet have lock on any user
    6756             :      * table, we MUST NOT invoke any server-side data collection functions
    6757             :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    6758             :      * wrong answers if any concurrent DDL is happening.
    6759             :      */
    6760             : 
    6761         306 :     appendPQExpBufferStr(query,
    6762             :                          "SELECT c.tableoid, c.oid, c.relname, "
    6763             :                          "c.relnamespace, c.relkind, c.reltype, "
    6764             :                          "c.relowner, "
    6765             :                          "c.relchecks, "
    6766             :                          "c.relhasindex, c.relhasrules, c.relpages, "
    6767             :                          "c.relhastriggers, "
    6768             :                          "c.relpersistence, "
    6769             :                          "c.reloftype, "
    6770             :                          "c.relacl, "
    6771             :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    6772             :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    6773             :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    6774             :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    6775             :                          "ELSE 0 END AS foreignserver, "
    6776             :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    6777             :                          "tc.oid AS toid, "
    6778             :                          "tc.relpages AS toastpages, "
    6779             :                          "tc.reloptions AS toast_reloptions, "
    6780             :                          "d.refobjid AS owning_tab, "
    6781             :                          "d.refobjsubid AS owning_col, "
    6782             :                          "tsp.spcname AS reltablespace, ");
    6783             : 
    6784         306 :     if (fout->remoteVersion >= 120000)
    6785         306 :         appendPQExpBufferStr(query,
    6786             :                              "false AS relhasoids, ");
    6787             :     else
    6788           0 :         appendPQExpBufferStr(query,
    6789             :                              "c.relhasoids, ");
    6790             : 
    6791         306 :     if (fout->remoteVersion >= 90300)
    6792         306 :         appendPQExpBufferStr(query,
    6793             :                              "c.relispopulated, ");
    6794             :     else
    6795           0 :         appendPQExpBufferStr(query,
    6796             :                              "'t' as relispopulated, ");
    6797             : 
    6798         306 :     if (fout->remoteVersion >= 90400)
    6799         306 :         appendPQExpBufferStr(query,
    6800             :                              "c.relreplident, ");
    6801             :     else
    6802           0 :         appendPQExpBufferStr(query,
    6803             :                              "'d' AS relreplident, ");
    6804             : 
    6805         306 :     if (fout->remoteVersion >= 90500)
    6806         306 :         appendPQExpBufferStr(query,
    6807             :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    6808             :     else
    6809           0 :         appendPQExpBufferStr(query,
    6810             :                              "false AS relrowsecurity, "
    6811             :                              "false AS relforcerowsecurity, ");
    6812             : 
    6813         306 :     if (fout->remoteVersion >= 90300)
    6814         306 :         appendPQExpBufferStr(query,
    6815             :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    6816             :     else
    6817           0 :         appendPQExpBufferStr(query,
    6818             :                              "0 AS relminmxid, 0 AS tminmxid, ");
    6819             : 
    6820         306 :     if (fout->remoteVersion >= 90300)
    6821         306 :         appendPQExpBufferStr(query,
    6822             :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    6823             :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    6824             :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    6825             :     else
    6826           0 :         appendPQExpBufferStr(query,
    6827             :                              "c.reloptions, NULL AS checkoption, ");
    6828             : 
    6829         306 :     if (fout->remoteVersion >= 90600)
    6830         306 :         appendPQExpBufferStr(query,
    6831             :                              "am.amname, ");
    6832             :     else
    6833           0 :         appendPQExpBufferStr(query,
    6834             :                              "NULL AS amname, ");
    6835             : 
    6836         306 :     if (fout->remoteVersion >= 90600)
    6837         306 :         appendPQExpBufferStr(query,
    6838             :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    6839             :     else
    6840           0 :         appendPQExpBufferStr(query,
    6841             :                              "false AS is_identity_sequence, ");
    6842             : 
    6843         306 :     if (fout->remoteVersion >= 100000)
    6844         306 :         appendPQExpBufferStr(query,
    6845             :                              "c.relispartition AS ispartition ");
    6846             :     else
    6847           0 :         appendPQExpBufferStr(query,
    6848             :                              "false AS ispartition ");
    6849             : 
    6850             :     /*
    6851             :      * Left join to pg_depend to pick up dependency info linking sequences to
    6852             :      * their owning column, if any (note this dependency is AUTO except for
    6853             :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    6854             :      * collect the spcname.
    6855             :      */
    6856         306 :     appendPQExpBufferStr(query,
    6857             :                          "\nFROM pg_class c\n"
    6858             :                          "LEFT JOIN pg_depend d ON "
    6859             :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    6860             :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    6861             :                          "d.objsubid = 0 AND "
    6862             :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    6863             :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    6864             : 
    6865             :     /*
    6866             :      * In 9.6 and up, left join to pg_am to pick up the amname.
    6867             :      */
    6868         306 :     if (fout->remoteVersion >= 90600)
    6869         306 :         appendPQExpBufferStr(query,
    6870             :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    6871             : 
    6872             :     /*
    6873             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    6874             :      * that versions 10 and 11 have them, but later versions do not, so
    6875             :      * emitting them causes the upgrade to fail.
    6876             :      */
    6877         306 :     appendPQExpBufferStr(query,
    6878             :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    6879             :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    6880             :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    6881             : 
    6882             :     /*
    6883             :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    6884             :      * relkinds are possible in older servers, but it's not worth the trouble
    6885             :      * to emit a version-dependent list.
    6886             :      *
    6887             :      * Composite-type table entries won't be dumped as such, but we have to
    6888             :      * make a DumpableObject for them so that we can track dependencies of the
    6889             :      * composite type (pg_depend entries for columns of the composite type
    6890             :      * link to the pg_class entry not the pg_type entry).
    6891             :      */
    6892         306 :     appendPQExpBufferStr(query,
    6893             :                          "WHERE c.relkind IN ("
    6894             :                          CppAsString2(RELKIND_RELATION) ", "
    6895             :                          CppAsString2(RELKIND_SEQUENCE) ", "
    6896             :                          CppAsString2(RELKIND_VIEW) ", "
    6897             :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    6898             :                          CppAsString2(RELKIND_MATVIEW) ", "
    6899             :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    6900             :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    6901             :                          "ORDER BY c.oid");
    6902             : 
    6903         306 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6904             : 
    6905         306 :     ntups = PQntuples(res);
    6906             : 
    6907         306 :     *numTables = ntups;
    6908             : 
    6909             :     /*
    6910             :      * Extract data from result and lock dumpable tables.  We do the locking
    6911             :      * before anything else, to minimize the window wherein a table could
    6912             :      * disappear under us.
    6913             :      *
    6914             :      * Note that we have to save info about all tables here, even when dumping
    6915             :      * only one, because we don't yet know which tables might be inheritance
    6916             :      * ancestors of the target table.
    6917             :      */
    6918         306 :     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    6919             : 
    6920         306 :     i_reltableoid = PQfnumber(res, "tableoid");
    6921         306 :     i_reloid = PQfnumber(res, "oid");
    6922         306 :     i_relname = PQfnumber(res, "relname");
    6923         306 :     i_relnamespace = PQfnumber(res, "relnamespace");
    6924         306 :     i_relkind = PQfnumber(res, "relkind");
    6925         306 :     i_reltype = PQfnumber(res, "reltype");
    6926         306 :     i_relowner = PQfnumber(res, "relowner");
    6927         306 :     i_relchecks = PQfnumber(res, "relchecks");
    6928         306 :     i_relhasindex = PQfnumber(res, "relhasindex");
    6929         306 :     i_relhasrules = PQfnumber(res, "relhasrules");
    6930         306 :     i_relpages = PQfnumber(res, "relpages");
    6931         306 :     i_toastpages = PQfnumber(res, "toastpages");
    6932         306 :     i_owning_tab = PQfnumber(res, "owning_tab");
    6933         306 :     i_owning_col = PQfnumber(res, "owning_col");
    6934         306 :     i_reltablespace = PQfnumber(res, "reltablespace");
    6935         306 :     i_relhasoids = PQfnumber(res, "relhasoids");
    6936         306 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    6937         306 :     i_relpersistence = PQfnumber(res, "relpersistence");
    6938         306 :     i_relispopulated = PQfnumber(res, "relispopulated");
    6939         306 :     i_relreplident = PQfnumber(res, "relreplident");
    6940         306 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    6941         306 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    6942         306 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    6943         306 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    6944         306 :     i_toastoid = PQfnumber(res, "toid");
    6945         306 :     i_relminmxid = PQfnumber(res, "relminmxid");
    6946         306 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    6947         306 :     i_reloptions = PQfnumber(res, "reloptions");
    6948         306 :     i_checkoption = PQfnumber(res, "checkoption");
    6949         306 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    6950         306 :     i_reloftype = PQfnumber(res, "reloftype");
    6951         306 :     i_foreignserver = PQfnumber(res, "foreignserver");
    6952         306 :     i_amname = PQfnumber(res, "amname");
    6953         306 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    6954         306 :     i_relacl = PQfnumber(res, "relacl");
    6955         306 :     i_acldefault = PQfnumber(res, "acldefault");
    6956         306 :     i_ispartition = PQfnumber(res, "ispartition");
    6957             : 
    6958         306 :     if (dopt->lockWaitTimeout)
    6959             :     {
    6960             :         /*
    6961             :          * Arrange to fail instead of waiting forever for a table lock.
    6962             :          *
    6963             :          * NB: this coding assumes that the only queries issued within the
    6964             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    6965             :          * applied to other things too.
    6966             :          */
    6967           4 :         resetPQExpBuffer(query);
    6968           4 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    6969           4 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    6970           4 :         ExecuteSqlStatement(fout, query->data);
    6971             :     }
    6972             : 
    6973         306 :     resetPQExpBuffer(query);
    6974             : 
    6975       77730 :     for (i = 0; i < ntups; i++)
    6976             :     {
    6977       77424 :         tblinfo[i].dobj.objType = DO_TABLE;
    6978       77424 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    6979       77424 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    6980       77424 :         AssignDumpId(&tblinfo[i].dobj);
    6981       77424 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    6982      154848 :         tblinfo[i].dobj.namespace =
    6983       77424 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    6984       77424 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    6985       77424 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6986       77424 :         tblinfo[i].dacl.privtype = 0;
    6987       77424 :         tblinfo[i].dacl.initprivs = NULL;
    6988       77424 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    6989       77424 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    6990       77424 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    6991       77424 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    6992       77424 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    6993       77424 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    6994       77424 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    6995       77424 :         if (PQgetisnull(res, i, i_toastpages))
    6996       61380 :             tblinfo[i].toastpages = 0;
    6997             :         else
    6998       16044 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    6999       77424 :         if (PQgetisnull(res, i, i_owning_tab))
    7000             :         {
    7001       76810 :             tblinfo[i].owning_tab = InvalidOid;
    7002       76810 :             tblinfo[i].owning_col = 0;
    7003             :         }
    7004             :         else
    7005             :         {
    7006         614 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7007         614 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7008             :         }
    7009       77424 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7010       77424 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7011       77424 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7012       77424 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7013       77424 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7014       77424 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7015       77424 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7016       77424 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7017       77424 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7018       77424 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7019       77424 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7020       77424 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7021       77424 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7022       77424 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7023       77424 :         if (PQgetisnull(res, i, i_checkoption))
    7024       77336 :             tblinfo[i].checkoption = NULL;
    7025             :         else
    7026          88 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7027       77424 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7028       77424 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7029       77424 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7030       77424 :         if (PQgetisnull(res, i, i_amname))
    7031       46682 :             tblinfo[i].amname = NULL;
    7032             :         else
    7033       30742 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7034       77424 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7035       77424 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7036             : 
    7037             :         /* other fields were zeroed above */
    7038             : 
    7039             :         /*
    7040             :          * Decide whether we want to dump this table.
    7041             :          */
    7042       77424 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7043         298 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7044             :         else
    7045       77126 :             selectDumpableTable(&tblinfo[i], fout);
    7046             : 
    7047             :         /*
    7048             :          * Now, consider the table "interesting" if we need to dump its
    7049             :          * definition or its data.  Later on, we'll skip a lot of data
    7050             :          * collection for uninteresting tables.
    7051             :          *
    7052             :          * Note: the "interesting" flag will also be set by flagInhTables for
    7053             :          * parents of interesting tables, so that we collect necessary
    7054             :          * inheritance info even when the parents are not themselves being
    7055             :          * dumped.  This is the main reason why we need an "interesting" flag
    7056             :          * that's separate from the components-to-dump bitmask.
    7057             :          */
    7058       77424 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7059             :                                   (DUMP_COMPONENT_DEFINITION |
    7060       77424 :                                    DUMP_COMPONENT_DATA)) != 0;
    7061             : 
    7062       77424 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7063       77424 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7064             : 
    7065             :         /* Tables have data */
    7066       77424 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7067             : 
    7068             :         /* Mark whether table has an ACL */
    7069       77424 :         if (!PQgetisnull(res, i, i_relacl))
    7070       63496 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7071       77424 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7072             : 
    7073             :         /*
    7074             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7075             :          * in schema before we get around to dumping them.
    7076             :          *
    7077             :          * Note that we don't explicitly lock parents of the target tables; we
    7078             :          * assume our lock on the child is enough to prevent schema
    7079             :          * alterations to parent tables.
    7080             :          *
    7081             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7082             :          * plain or partitioned tables, but the backend doesn't presently
    7083             :          * allow that.
    7084             :          *
    7085             :          * We only need to lock the table for certain components; see
    7086             :          * pg_dump.h
    7087             :          */
    7088       77424 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7089       11612 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7090        3264 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7091             :         {
    7092             :             /*
    7093             :              * Tables are locked in batches.  When dumping from a remote
    7094             :              * server this can save a significant amount of time by reducing
    7095             :              * the number of round trips.
    7096             :              */
    7097        9378 :             if (query->len == 0)
    7098         194 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7099         194 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7100             :             else
    7101             :             {
    7102        9184 :                 appendPQExpBuffer(query, ", %s",
    7103        9184 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7104             : 
    7105             :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7106        9184 :                 if (query->len >= 100000)
    7107             :                 {
    7108             :                     /* Lock another batch of tables. */
    7109           0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7110           0 :                     ExecuteSqlStatement(fout, query->data);
    7111           0 :                     resetPQExpBuffer(query);
    7112             :                 }
    7113             :             }
    7114             :         }
    7115             :     }
    7116             : 
    7117         306 :     if (query->len != 0)
    7118             :     {
    7119             :         /* Lock the tables in the last batch. */
    7120         194 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7121         194 :         ExecuteSqlStatement(fout, query->data);
    7122             :     }
    7123             : 
    7124         304 :     if (dopt->lockWaitTimeout)
    7125             :     {
    7126           4 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7127             :     }
    7128             : 
    7129         304 :     PQclear(res);
    7130             : 
    7131         304 :     destroyPQExpBuffer(query);
    7132             : 
    7133         304 :     return tblinfo;
    7134             : }
    7135             : 
    7136             : /*
    7137             :  * getOwnedSeqs
    7138             :  *    identify owned sequences and mark them as dumpable if owning table is
    7139             :  *
    7140             :  * We used to do this in getTables(), but it's better to do it after the
    7141             :  * index used by findTableByOid() has been set up.
    7142             :  */
    7143             : void
    7144         304 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7145             : {
    7146             :     int         i;
    7147             : 
    7148             :     /*
    7149             :      * Force sequences that are "owned" by table columns to be dumped whenever
    7150             :      * their owning table is being dumped.
    7151             :      */
    7152       77210 :     for (i = 0; i < numTables; i++)
    7153             :     {
    7154       76906 :         TableInfo  *seqinfo = &tblinfo[i];
    7155             :         TableInfo  *owning_tab;
    7156             : 
    7157       76906 :         if (!OidIsValid(seqinfo->owning_tab))
    7158       76298 :             continue;           /* not an owned sequence */
    7159             : 
    7160         608 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7161         608 :         if (owning_tab == NULL)
    7162           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7163             :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7164             : 
    7165             :         /*
    7166             :          * Only dump identity sequences if we're going to dump the table that
    7167             :          * it belongs to.
    7168             :          */
    7169         608 :         if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
    7170          52 :             seqinfo->is_identity_sequence)
    7171             :         {
    7172          14 :             seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
    7173          14 :             continue;
    7174             :         }
    7175             : 
    7176             :         /*
    7177             :          * Otherwise we need to dump the components that are being dumped for
    7178             :          * the table and any components which the sequence is explicitly
    7179             :          * marked with.
    7180             :          *
    7181             :          * We can't simply use the set of components which are being dumped
    7182             :          * for the table as the table might be in an extension (and only the
    7183             :          * non-extension components, eg: ACLs if changed, security labels, and
    7184             :          * policies, are being dumped) while the sequence is not (and
    7185             :          * therefore the definition and other components should also be
    7186             :          * dumped).
    7187             :          *
    7188             :          * If the sequence is part of the extension then it should be properly
    7189             :          * marked by checkExtensionMembership() and this will be a no-op as
    7190             :          * the table will be equivalently marked.
    7191             :          */
    7192         594 :         seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
    7193             : 
    7194         594 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7195         560 :             seqinfo->interesting = true;
    7196             :     }
    7197         304 : }
    7198             : 
    7199             : /*
    7200             :  * getInherits
    7201             :  *    read all the inheritance information
    7202             :  * from the system catalogs return them in the InhInfo* structure
    7203             :  *
    7204             :  * numInherits is set to the number of pairs read in
    7205             :  */
    7206             : InhInfo *
    7207         304 : getInherits(Archive *fout, int *numInherits)
    7208             : {
    7209             :     PGresult   *res;
    7210             :     int         ntups;
    7211             :     int         i;
    7212         304 :     PQExpBuffer query = createPQExpBuffer();
    7213             :     InhInfo    *inhinfo;
    7214             : 
    7215             :     int         i_inhrelid;
    7216             :     int         i_inhparent;
    7217             : 
    7218             :     /* find all the inheritance information */
    7219         304 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7220             : 
    7221         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7222             : 
    7223         304 :     ntups = PQntuples(res);
    7224             : 
    7225         304 :     *numInherits = ntups;
    7226             : 
    7227         304 :     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    7228             : 
    7229         304 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7230         304 :     i_inhparent = PQfnumber(res, "inhparent");
    7231             : 
    7232        4914 :     for (i = 0; i < ntups; i++)
    7233             :     {
    7234        4610 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7235        4610 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7236             :     }
    7237             : 
    7238         304 :     PQclear(res);
    7239             : 
    7240         304 :     destroyPQExpBuffer(query);
    7241             : 
    7242         304 :     return inhinfo;
    7243             : }
    7244             : 
    7245             : /*
    7246             :  * getPartitioningInfo
    7247             :  *    get information about partitioning
    7248             :  *
    7249             :  * For the most part, we only collect partitioning info about tables we
    7250             :  * intend to dump.  However, this function has to consider all partitioned
    7251             :  * tables in the database, because we need to know about parents of partitions
    7252             :  * we are going to dump even if the parents themselves won't be dumped.
    7253             :  *
    7254             :  * Specifically, what we need to know is whether each partitioned table
    7255             :  * has an "unsafe" partitioning scheme that requires us to force
    7256             :  * load-via-partition-root mode for its children.  Currently the only case
    7257             :  * for which we force that is hash partitioning on enum columns, since the
    7258             :  * hash codes depend on enum value OIDs which won't be replicated across
    7259             :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7260             :  * might be necessary, but we expect users to cope with them.
    7261             :  */
    7262             : void
    7263         304 : getPartitioningInfo(Archive *fout)
    7264             : {
    7265             :     PQExpBuffer query;
    7266             :     PGresult   *res;
    7267             :     int         ntups;
    7268             : 
    7269             :     /* hash partitioning didn't exist before v11 */
    7270         304 :     if (fout->remoteVersion < 110000)
    7271           0 :         return;
    7272             :     /* needn't bother if schema-only dump */
    7273         304 :     if (fout->dopt->schemaOnly)
    7274          32 :         return;
    7275             : 
    7276         272 :     query = createPQExpBuffer();
    7277             : 
    7278             :     /*
    7279             :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7280             :      * appears among the partition opclasses.  We needn't check partstrat.
    7281             :      *
    7282             :      * Note that this query may well retrieve info about tables we aren't
    7283             :      * going to dump and hence have no lock on.  That's okay since we need not
    7284             :      * invoke any unsafe server-side functions.
    7285             :      */
    7286         272 :     appendPQExpBufferStr(query,
    7287             :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7288             :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7289             :                          "ON c.opcmethod = a.oid\n"
    7290             :                          "WHERE opcname = 'enum_ops' "
    7291             :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7292             :                          "AND amname = 'hash') = ANY(partclass)");
    7293             : 
    7294         272 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7295             : 
    7296         272 :     ntups = PQntuples(res);
    7297             : 
    7298         276 :     for (int i = 0; i < ntups; i++)
    7299             :     {
    7300           4 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7301             :         TableInfo  *tbinfo;
    7302             : 
    7303           4 :         tbinfo = findTableByOid(tabrelid);
    7304           4 :         if (tbinfo == NULL)
    7305           0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7306             :                      tabrelid);
    7307           4 :         tbinfo->unsafe_partitions = true;
    7308             :     }
    7309             : 
    7310         272 :     PQclear(res);
    7311             : 
    7312         272 :     destroyPQExpBuffer(query);
    7313             : }
    7314             : 
    7315             : /*
    7316             :  * getIndexes
    7317             :  *    get information about every index on a dumpable table
    7318             :  *
    7319             :  * Note: index data is not returned directly to the caller, but it
    7320             :  * does get entered into the DumpableObject tables.
    7321             :  */
    7322             : void
    7323         304 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7324             : {
    7325         304 :     PQExpBuffer query = createPQExpBuffer();
    7326         304 :     PQExpBuffer tbloids = createPQExpBuffer();
    7327             :     PGresult   *res;
    7328             :     int         ntups;
    7329             :     int         curtblindx;
    7330             :     IndxInfo   *indxinfo;
    7331             :     int         i_tableoid,
    7332             :                 i_oid,
    7333             :                 i_indrelid,
    7334             :                 i_indexname,
    7335             :                 i_parentidx,
    7336             :                 i_indexdef,
    7337             :                 i_indnkeyatts,
    7338             :                 i_indnatts,
    7339             :                 i_indkey,
    7340             :                 i_indisclustered,
    7341             :                 i_indisreplident,
    7342             :                 i_indnullsnotdistinct,
    7343             :                 i_contype,
    7344             :                 i_conname,
    7345             :                 i_condeferrable,
    7346             :                 i_condeferred,
    7347             :                 i_conperiod,
    7348             :                 i_contableoid,
    7349             :                 i_conoid,
    7350             :                 i_condef,
    7351             :                 i_tablespace,
    7352             :                 i_indreloptions,
    7353             :                 i_indstatcols,
    7354             :                 i_indstatvals;
    7355             : 
    7356             :     /*
    7357             :      * We want to perform just one query against pg_index.  However, we
    7358             :      * mustn't try to select every row of the catalog and then sort it out on
    7359             :      * the client side, because some of the server-side functions we need
    7360             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7361             :      * build an array of the OIDs of tables we care about (and now have lock
    7362             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7363             :      */
    7364         304 :     appendPQExpBufferChar(tbloids, '{');
    7365       77210 :     for (int i = 0; i < numTables; i++)
    7366             :     {
    7367       76906 :         TableInfo  *tbinfo = &tblinfo[i];
    7368             : 
    7369       76906 :         if (!tbinfo->hasindex)
    7370       54084 :             continue;
    7371             : 
    7372             :         /*
    7373             :          * We can ignore indexes of uninteresting tables.
    7374             :          */
    7375       22822 :         if (!tbinfo->interesting)
    7376       19500 :             continue;
    7377             : 
    7378             :         /* OK, we need info for this table */
    7379        3322 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7380        3174 :             appendPQExpBufferChar(tbloids, ',');
    7381        3322 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7382             :     }
    7383         304 :     appendPQExpBufferChar(tbloids, '}');
    7384             : 
    7385         304 :     appendPQExpBufferStr(query,
    7386             :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7387             :                          "t.relname AS indexname, "
    7388             :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7389             :                          "i.indkey, i.indisclustered, "
    7390             :                          "c.contype, c.conname, "
    7391             :                          "c.condeferrable, c.condeferred, "
    7392             :                          "c.tableoid AS contableoid, "
    7393             :                          "c.oid AS conoid, "
    7394             :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7395             :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7396             :                          "t.reloptions AS indreloptions, ");
    7397             : 
    7398             : 
    7399         304 :     if (fout->remoteVersion >= 90400)
    7400         304 :         appendPQExpBufferStr(query,
    7401             :                              "i.indisreplident, ");
    7402             :     else
    7403           0 :         appendPQExpBufferStr(query,
    7404             :                              "false AS indisreplident, ");
    7405             : 
    7406         304 :     if (fout->remoteVersion >= 110000)
    7407         304 :         appendPQExpBufferStr(query,
    7408             :                              "inh.inhparent AS parentidx, "
    7409             :                              "i.indnkeyatts AS indnkeyatts, "
    7410             :                              "i.indnatts AS indnatts, "
    7411             :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7412             :                              "  FROM pg_catalog.pg_attribute "
    7413             :                              "  WHERE attrelid = i.indexrelid AND "
    7414             :                              "    attstattarget >= 0) AS indstatcols, "
    7415             :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7416             :                              "  FROM pg_catalog.pg_attribute "
    7417             :                              "  WHERE attrelid = i.indexrelid AND "
    7418             :                              "    attstattarget >= 0) AS indstatvals, ");
    7419             :     else
    7420           0 :         appendPQExpBufferStr(query,
    7421             :                              "0 AS parentidx, "
    7422             :                              "i.indnatts AS indnkeyatts, "
    7423             :                              "i.indnatts AS indnatts, "
    7424             :                              "'' AS indstatcols, "
    7425             :                              "'' AS indstatvals, ");
    7426             : 
    7427         304 :     if (fout->remoteVersion >= 150000)
    7428         304 :         appendPQExpBufferStr(query,
    7429             :                              "i.indnullsnotdistinct, ");
    7430             :     else
    7431           0 :         appendPQExpBufferStr(query,
    7432             :                              "false AS indnullsnotdistinct, ");
    7433             : 
    7434         304 :     if (fout->remoteVersion >= 170000)
    7435         304 :         appendPQExpBufferStr(query,
    7436             :                              "c.conperiod ");
    7437             :     else
    7438           0 :         appendPQExpBufferStr(query,
    7439             :                              "NULL AS conperiod ");
    7440             : 
    7441             :     /*
    7442             :      * The point of the messy-looking outer join is to find a constraint that
    7443             :      * is related by an internal dependency link to the index. If we find one,
    7444             :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7445             :      * index won't have more than one internal dependency.
    7446             :      *
    7447             :      * Note: the check on conrelid is redundant, but useful because that
    7448             :      * column is indexed while conindid is not.
    7449             :      */
    7450         304 :     if (fout->remoteVersion >= 110000)
    7451             :     {
    7452         304 :         appendPQExpBuffer(query,
    7453             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7454             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7455             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7456             :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7457             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7458             :                           "ON (i.indrelid = c.conrelid AND "
    7459             :                           "i.indexrelid = c.conindid AND "
    7460             :                           "c.contype IN ('p','u','x')) "
    7461             :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    7462             :                           "ON (inh.inhrelid = indexrelid) "
    7463             :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    7464             :                           "AND i.indisready "
    7465             :                           "ORDER BY i.indrelid, indexname",
    7466             :                           tbloids->data);
    7467             :     }
    7468             :     else
    7469             :     {
    7470             :         /*
    7471             :          * the test on indisready is necessary in 9.2, and harmless in
    7472             :          * earlier/later versions
    7473             :          */
    7474           0 :         appendPQExpBuffer(query,
    7475             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7476             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7477             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7478             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7479             :                           "ON (i.indrelid = c.conrelid AND "
    7480             :                           "i.indexrelid = c.conindid AND "
    7481             :                           "c.contype IN ('p','u','x')) "
    7482             :                           "WHERE i.indisvalid AND i.indisready "
    7483             :                           "ORDER BY i.indrelid, indexname",
    7484             :                           tbloids->data);
    7485             :     }
    7486             : 
    7487         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7488             : 
    7489         304 :     ntups = PQntuples(res);
    7490             : 
    7491         304 :     i_tableoid = PQfnumber(res, "tableoid");
    7492         304 :     i_oid = PQfnumber(res, "oid");
    7493         304 :     i_indrelid = PQfnumber(res, "indrelid");
    7494         304 :     i_indexname = PQfnumber(res, "indexname");
    7495         304 :     i_parentidx = PQfnumber(res, "parentidx");
    7496         304 :     i_indexdef = PQfnumber(res, "indexdef");
    7497         304 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    7498         304 :     i_indnatts = PQfnumber(res, "indnatts");
    7499         304 :     i_indkey = PQfnumber(res, "indkey");
    7500         304 :     i_indisclustered = PQfnumber(res, "indisclustered");
    7501         304 :     i_indisreplident = PQfnumber(res, "indisreplident");
    7502         304 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    7503         304 :     i_contype = PQfnumber(res, "contype");
    7504         304 :     i_conname = PQfnumber(res, "conname");
    7505         304 :     i_condeferrable = PQfnumber(res, "condeferrable");
    7506         304 :     i_condeferred = PQfnumber(res, "condeferred");
    7507         304 :     i_conperiod = PQfnumber(res, "conperiod");
    7508         304 :     i_contableoid = PQfnumber(res, "contableoid");
    7509         304 :     i_conoid = PQfnumber(res, "conoid");
    7510         304 :     i_condef = PQfnumber(res, "condef");
    7511         304 :     i_tablespace = PQfnumber(res, "tablespace");
    7512         304 :     i_indreloptions = PQfnumber(res, "indreloptions");
    7513         304 :     i_indstatcols = PQfnumber(res, "indstatcols");
    7514         304 :     i_indstatvals = PQfnumber(res, "indstatvals");
    7515             : 
    7516         304 :     indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    7517             : 
    7518             :     /*
    7519             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    7520             :      * j is handled by the inner loop.
    7521             :      */
    7522         304 :     curtblindx = -1;
    7523        3618 :     for (int j = 0; j < ntups;)
    7524             :     {
    7525        3314 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    7526        3314 :         TableInfo  *tbinfo = NULL;
    7527             :         int         numinds;
    7528             : 
    7529             :         /* Count rows for this table */
    7530        4256 :         for (numinds = 1; numinds < ntups - j; numinds++)
    7531        4108 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    7532        3166 :                 break;
    7533             : 
    7534             :         /*
    7535             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7536             :          * order.
    7537             :          */
    7538       42884 :         while (++curtblindx < numTables)
    7539             :         {
    7540       42884 :             tbinfo = &tblinfo[curtblindx];
    7541       42884 :             if (tbinfo->dobj.catId.oid == indrelid)
    7542        3314 :                 break;
    7543             :         }
    7544        3314 :         if (curtblindx >= numTables)
    7545           0 :             pg_fatal("unrecognized table OID %u", indrelid);
    7546             :         /* cross-check that we only got requested tables */
    7547        3314 :         if (!tbinfo->hasindex ||
    7548        3314 :             !tbinfo->interesting)
    7549           0 :             pg_fatal("unexpected index data for table \"%s\"",
    7550             :                      tbinfo->dobj.name);
    7551             : 
    7552             :         /* Save data for this table */
    7553        3314 :         tbinfo->indexes = indxinfo + j;
    7554        3314 :         tbinfo->numIndexes = numinds;
    7555             : 
    7556        7570 :         for (int c = 0; c < numinds; c++, j++)
    7557             :         {
    7558             :             char        contype;
    7559             : 
    7560        4256 :             indxinfo[j].dobj.objType = DO_INDEX;
    7561        4256 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    7562        4256 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    7563        4256 :             AssignDumpId(&indxinfo[j].dobj);
    7564        4256 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    7565        4256 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    7566        4256 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7567        4256 :             indxinfo[j].indextable = tbinfo;
    7568        4256 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    7569        4256 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    7570        4256 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    7571        4256 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    7572        4256 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    7573        4256 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    7574        4256 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    7575        4256 :             indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    7576        4256 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    7577        4256 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    7578        4256 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    7579        4256 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    7580        4256 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    7581        4256 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    7582        4256 :             indxinfo[j].partattaches = (SimplePtrList)
    7583             :             {
    7584             :                 NULL, NULL
    7585             :             };
    7586        4256 :             contype = *(PQgetvalue(res, j, i_contype));
    7587             : 
    7588        4256 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    7589        2320 :             {
    7590             :                 /*
    7591             :                  * If we found a constraint matching the index, create an
    7592             :                  * entry for it.
    7593             :                  */
    7594             :                 ConstraintInfo *constrinfo;
    7595             : 
    7596        2320 :                 constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
    7597        2320 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    7598        2320 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7599        2320 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7600        2320 :                 AssignDumpId(&constrinfo->dobj);
    7601        2320 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    7602        2320 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7603        2320 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    7604        2320 :                 constrinfo->contable = tbinfo;
    7605        2320 :                 constrinfo->condomain = NULL;
    7606        2320 :                 constrinfo->contype = contype;
    7607        2320 :                 if (contype == 'x')
    7608          20 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7609             :                 else
    7610        2300 :                     constrinfo->condef = NULL;
    7611        2320 :                 constrinfo->confrelid = InvalidOid;
    7612        2320 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    7613        2320 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    7614        2320 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    7615        2320 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    7616        2320 :                 constrinfo->conislocal = true;
    7617        2320 :                 constrinfo->separate = true;
    7618             : 
    7619        2320 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    7620             :             }
    7621             :             else
    7622             :             {
    7623             :                 /* Plain secondary index */
    7624        1936 :                 indxinfo[j].indexconstraint = 0;
    7625             :             }
    7626             :         }
    7627             :     }
    7628             : 
    7629         304 :     PQclear(res);
    7630             : 
    7631         304 :     destroyPQExpBuffer(query);
    7632         304 :     destroyPQExpBuffer(tbloids);
    7633         304 : }
    7634             : 
    7635             : /*
    7636             :  * getExtendedStatistics
    7637             :  *    get information about extended-statistics objects.
    7638             :  *
    7639             :  * Note: extended statistics data is not returned directly to the caller, but
    7640             :  * it does get entered into the DumpableObject tables.
    7641             :  */
    7642             : void
    7643         304 : getExtendedStatistics(Archive *fout)
    7644             : {
    7645             :     PQExpBuffer query;
    7646             :     PGresult   *res;
    7647             :     StatsExtInfo *statsextinfo;
    7648             :     int         ntups;
    7649             :     int         i_tableoid;
    7650             :     int         i_oid;
    7651             :     int         i_stxname;
    7652             :     int         i_stxnamespace;
    7653             :     int         i_stxowner;
    7654             :     int         i_stxrelid;
    7655             :     int         i_stattarget;
    7656             :     int         i;
    7657             : 
    7658             :     /* Extended statistics were new in v10 */
    7659         304 :     if (fout->remoteVersion < 100000)
    7660           0 :         return;
    7661             : 
    7662         304 :     query = createPQExpBuffer();
    7663             : 
    7664         304 :     if (fout->remoteVersion < 130000)
    7665           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    7666             :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    7667             :                              "FROM pg_catalog.pg_statistic_ext");
    7668             :     else
    7669         304 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    7670             :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    7671             :                              "FROM pg_catalog.pg_statistic_ext");
    7672             : 
    7673         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7674             : 
    7675         304 :     ntups = PQntuples(res);
    7676             : 
    7677         304 :     i_tableoid = PQfnumber(res, "tableoid");
    7678         304 :     i_oid = PQfnumber(res, "oid");
    7679         304 :     i_stxname = PQfnumber(res, "stxname");
    7680         304 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    7681         304 :     i_stxowner = PQfnumber(res, "stxowner");
    7682         304 :     i_stxrelid = PQfnumber(res, "stxrelid");
    7683         304 :     i_stattarget = PQfnumber(res, "stxstattarget");
    7684             : 
    7685         304 :     statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    7686             : 
    7687         602 :     for (i = 0; i < ntups; i++)
    7688             :     {
    7689         298 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    7690         298 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7691         298 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7692         298 :         AssignDumpId(&statsextinfo[i].dobj);
    7693         298 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    7694         596 :         statsextinfo[i].dobj.namespace =
    7695         298 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    7696         298 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    7697         596 :         statsextinfo[i].stattable =
    7698         298 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    7699         298 :         if (PQgetisnull(res, i, i_stattarget))
    7700         212 :             statsextinfo[i].stattarget = -1;
    7701             :         else
    7702          86 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    7703             : 
    7704             :         /* Decide whether we want to dump it */
    7705         298 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    7706             :     }
    7707             : 
    7708         304 :     PQclear(res);
    7709         304 :     destroyPQExpBuffer(query);
    7710             : }
    7711             : 
    7712             : /*
    7713             :  * getConstraints
    7714             :  *
    7715             :  * Get info about constraints on dumpable tables.
    7716             :  *
    7717             :  * Currently handles foreign keys only.
    7718             :  * Unique and primary key constraints are handled with indexes,
    7719             :  * while check constraints are processed in getTableAttrs().
    7720             :  */
    7721             : void
    7722         304 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    7723             : {
    7724         304 :     PQExpBuffer query = createPQExpBuffer();
    7725         304 :     PQExpBuffer tbloids = createPQExpBuffer();
    7726             :     PGresult   *res;
    7727             :     int         ntups;
    7728             :     int         curtblindx;
    7729         304 :     TableInfo  *tbinfo = NULL;
    7730             :     ConstraintInfo *constrinfo;
    7731             :     int         i_contableoid,
    7732             :                 i_conoid,
    7733             :                 i_conrelid,
    7734             :                 i_conname,
    7735             :                 i_confrelid,
    7736             :                 i_conindid,
    7737             :                 i_condef;
    7738             : 
    7739             :     /*
    7740             :      * We want to perform just one query against pg_constraint.  However, we
    7741             :      * mustn't try to select every row of the catalog and then sort it out on
    7742             :      * the client side, because some of the server-side functions we need
    7743             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7744             :      * build an array of the OIDs of tables we care about (and now have lock
    7745             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7746             :      */
    7747         304 :     appendPQExpBufferChar(tbloids, '{');
    7748       77210 :     for (int i = 0; i < numTables; i++)
    7749             :     {
    7750       76906 :         TableInfo  *tinfo = &tblinfo[i];
    7751             : 
    7752             :         /*
    7753             :          * For partitioned tables, foreign keys have no triggers so they must
    7754             :          * be included anyway in case some foreign keys are defined.
    7755             :          */
    7756       76906 :         if ((!tinfo->hastriggers &&
    7757       75128 :              tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
    7758        2456 :             !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    7759       74580 :             continue;
    7760             : 
    7761             :         /* OK, we need info for this table */
    7762        2326 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7763        2224 :             appendPQExpBufferChar(tbloids, ',');
    7764        2326 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    7765             :     }
    7766         304 :     appendPQExpBufferChar(tbloids, '}');
    7767             : 
    7768         304 :     appendPQExpBufferStr(query,
    7769             :                          "SELECT c.tableoid, c.oid, "
    7770             :                          "conrelid, conname, confrelid, ");
    7771         304 :     if (fout->remoteVersion >= 110000)
    7772         304 :         appendPQExpBufferStr(query, "conindid, ");
    7773             :     else
    7774           0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    7775         304 :     appendPQExpBuffer(query,
    7776             :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    7777             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7778             :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    7779             :                       "WHERE contype = 'f' ",
    7780             :                       tbloids->data);
    7781         304 :     if (fout->remoteVersion >= 110000)
    7782         304 :         appendPQExpBufferStr(query,
    7783             :                              "AND conparentid = 0 ");
    7784         304 :     appendPQExpBufferStr(query,
    7785             :                          "ORDER BY conrelid, conname");
    7786             : 
    7787         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7788             : 
    7789         304 :     ntups = PQntuples(res);
    7790             : 
    7791         304 :     i_contableoid = PQfnumber(res, "tableoid");
    7792         304 :     i_conoid = PQfnumber(res, "oid");
    7793         304 :     i_conrelid = PQfnumber(res, "conrelid");
    7794         304 :     i_conname = PQfnumber(res, "conname");
    7795         304 :     i_confrelid = PQfnumber(res, "confrelid");
    7796         304 :     i_conindid = PQfnumber(res, "conindid");
    7797         304 :     i_condef = PQfnumber(res, "condef");
    7798             : 
    7799         304 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    7800             : 
    7801         304 :     curtblindx = -1;
    7802         648 :     for (int j = 0; j < ntups; j++)
    7803             :     {
    7804         344 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    7805             :         TableInfo  *reftable;
    7806             : 
    7807             :         /*
    7808             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7809             :          * order.
    7810             :          */
    7811         344 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    7812             :         {
    7813       25048 :             while (++curtblindx < numTables)
    7814             :             {
    7815       25048 :                 tbinfo = &tblinfo[curtblindx];
    7816       25048 :                 if (tbinfo->dobj.catId.oid == conrelid)
    7817         324 :                     break;
    7818             :             }
    7819         324 :             if (curtblindx >= numTables)
    7820           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    7821             :         }
    7822             : 
    7823         344 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    7824         344 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7825         344 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7826         344 :         AssignDumpId(&constrinfo[j].dobj);
    7827         344 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7828         344 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7829         344 :         constrinfo[j].contable = tbinfo;
    7830         344 :         constrinfo[j].condomain = NULL;
    7831         344 :         constrinfo[j].contype = 'f';
    7832         344 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7833         344 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    7834         344 :         constrinfo[j].conindex = 0;
    7835         344 :         constrinfo[j].condeferrable = false;
    7836         344 :         constrinfo[j].condeferred = false;
    7837         344 :         constrinfo[j].conislocal = true;
    7838         344 :         constrinfo[j].separate = true;
    7839             : 
    7840             :         /*
    7841             :          * Restoring an FK that points to a partitioned table requires that
    7842             :          * all partition indexes have been attached beforehand. Ensure that
    7843             :          * happens by making the constraint depend on each index partition
    7844             :          * attach object.
    7845             :          */
    7846         344 :         reftable = findTableByOid(constrinfo[j].confrelid);
    7847         344 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    7848             :         {
    7849          40 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    7850             : 
    7851          40 :             if (indexOid != InvalidOid)
    7852             :             {
    7853          40 :                 for (int k = 0; k < reftable->numIndexes; k++)
    7854             :                 {
    7855             :                     IndxInfo   *refidx;
    7856             : 
    7857             :                     /* not our index? */
    7858          40 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    7859           0 :                         continue;
    7860             : 
    7861          40 :                     refidx = &reftable->indexes[k];
    7862          40 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    7863          40 :                     break;
    7864             :                 }
    7865             :             }
    7866             :         }
    7867             :     }
    7868             : 
    7869         304 :     PQclear(res);
    7870             : 
    7871         304 :     destroyPQExpBuffer(query);
    7872         304 :     destroyPQExpBuffer(tbloids);
    7873         304 : }
    7874             : 
    7875             : /*
    7876             :  * addConstrChildIdxDeps
    7877             :  *
    7878             :  * Recursive subroutine for getConstraints
    7879             :  *
    7880             :  * Given an object representing a foreign key constraint and an index on the
    7881             :  * partitioned table it references, mark the constraint object as dependent
    7882             :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    7883             :  * drilling down to their partitions if any.  This ensures that the FK is not
    7884             :  * restored until the index is fully marked valid.
    7885             :  */
    7886             : static void
    7887          90 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    7888             : {
    7889             :     SimplePtrListCell *cell;
    7890             : 
    7891             :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    7892             : 
    7893         310 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    7894             :     {
    7895         220 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    7896             : 
    7897         220 :         addObjectDependency(dobj, attach->dobj.dumpId);
    7898             : 
    7899         220 :         if (attach->partitionIdx->partattaches.head != NULL)
    7900          50 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    7901             :     }
    7902          90 : }
    7903             : 
    7904             : /*
    7905             :  * getDomainConstraints
    7906             :  *
    7907             :  * Get info about constraints on a domain.
    7908             :  */
    7909             : static void
    7910         262 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    7911             : {
    7912             :     int         i;
    7913             :     ConstraintInfo *constrinfo;
    7914         262 :     PQExpBuffer query = createPQExpBuffer();
    7915             :     PGresult   *res;
    7916             :     int         i_tableoid,
    7917             :                 i_oid,
    7918             :                 i_conname,
    7919             :                 i_consrc;
    7920             :     int         ntups;
    7921             : 
    7922         262 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    7923             :     {
    7924             :         /* Set up query for constraint-specific details */
    7925          82 :         appendPQExpBufferStr(query,
    7926             :                              "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    7927             :                              "SELECT tableoid, oid, conname, "
    7928             :                              "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    7929             :                              "convalidated "
    7930             :                              "FROM pg_catalog.pg_constraint "
    7931             :                              "WHERE contypid = $1 AND contype = 'c' "
    7932             :                              "ORDER BY conname");
    7933             : 
    7934          82 :         ExecuteSqlStatement(fout, query->data);
    7935             : 
    7936          82 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    7937             :     }
    7938             : 
    7939         262 :     printfPQExpBuffer(query,
    7940             :                       "EXECUTE getDomainConstraints('%u')",
    7941             :                       tyinfo->dobj.catId.oid);
    7942             : 
    7943         262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7944             : 
    7945         262 :     ntups = PQntuples(res);
    7946             : 
    7947         262 :     i_tableoid = PQfnumber(res, "tableoid");
    7948         262 :     i_oid = PQfnumber(res, "oid");
    7949         262 :     i_conname = PQfnumber(res, "conname");
    7950         262 :     i_consrc = PQfnumber(res, "consrc");
    7951             : 
    7952         262 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    7953             : 
    7954         262 :     tyinfo->nDomChecks = ntups;
    7955         262 :     tyinfo->domChecks = constrinfo;
    7956             : 
    7957         434 :     for (i = 0; i < ntups; i++)
    7958             :     {
    7959         172 :         bool        validated = PQgetvalue(res, i, 4)[0] == 't';
    7960             : 
    7961         172 :         constrinfo[i].dobj.objType = DO_CONSTRAINT;
    7962         172 :         constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7963         172 :         constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7964         172 :         AssignDumpId(&constrinfo[i].dobj);
    7965         172 :         constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    7966         172 :         constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
    7967         172 :         constrinfo[i].contable = NULL;
    7968         172 :         constrinfo[i].condomain = tyinfo;
    7969         172 :         constrinfo[i].contype = 'c';
    7970         172 :         constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    7971         172 :         constrinfo[i].confrelid = InvalidOid;
    7972         172 :         constrinfo[i].conindex = 0;
    7973         172 :         constrinfo[i].condeferrable = false;
    7974         172 :         constrinfo[i].condeferred = false;
    7975         172 :         constrinfo[i].conislocal = true;
    7976             : 
    7977         172 :         constrinfo[i].separate = !validated;
    7978             : 
    7979             :         /*
    7980             :          * Make the domain depend on the constraint, ensuring it won't be
    7981             :          * output till any constraint dependencies are OK.  If the constraint
    7982             :          * has not been validated, it's going to be dumped after the domain
    7983             :          * anyway, so this doesn't matter.
    7984             :          */
    7985         172 :         if (validated)
    7986         172 :             addObjectDependency(&tyinfo->dobj,
    7987         172 :                                 constrinfo[i].dobj.dumpId);
    7988             :     }
    7989             : 
    7990         262 :     PQclear(res);
    7991             : 
    7992         262 :     destroyPQExpBuffer(query);
    7993         262 : }
    7994             : 
    7995             : /*
    7996             :  * getRules
    7997             :  *    get basic information about every rule in the system
    7998             :  *
    7999             :  * numRules is set to the number of rules read in
    8000             :  */
    8001             : RuleInfo *
    8002         304 : getRules(Archive *fout, int *numRules)
    8003             : {
    8004             :     PGresult   *res;
    8005             :     int         ntups;
    8006             :     int         i;
    8007         304 :     PQExpBuffer query = createPQExpBuffer();
    8008             :     RuleInfo   *ruleinfo;
    8009             :     int         i_tableoid;
    8010             :     int         i_oid;
    8011             :     int         i_rulename;
    8012             :     int         i_ruletable;
    8013             :     int         i_ev_type;
    8014             :     int         i_is_instead;
    8015             :     int         i_ev_enabled;
    8016             : 
    8017         304 :     appendPQExpBufferStr(query, "SELECT "
    8018             :                          "tableoid, oid, rulename, "
    8019             :                          "ev_class AS ruletable, ev_type, is_instead, "
    8020             :                          "ev_enabled "
    8021             :                          "FROM pg_rewrite "
    8022             :                          "ORDER BY oid");
    8023             : 
    8024         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8025             : 
    8026         304 :     ntups = PQntuples(res);
    8027             : 
    8028         304 :     *numRules = ntups;
    8029             : 
    8030         304 :     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    8031             : 
    8032         304 :     i_tableoid = PQfnumber(res, "tableoid");
    8033         304 :     i_oid = PQfnumber(res, "oid");
    8034         304 :     i_rulename = PQfnumber(res, "rulename");
    8035         304 :     i_ruletable = PQfnumber(res, "ruletable");
    8036         304 :     i_ev_type = PQfnumber(res, "ev_type");
    8037         304 :     i_is_instead = PQfnumber(res, "is_instead");
    8038         304 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8039             : 
    8040       46184 :     for (i = 0; i < ntups; i++)
    8041             :     {
    8042             :         Oid         ruletableoid;
    8043             : 
    8044       45880 :         ruleinfo[i].dobj.objType = DO_RULE;
    8045       45880 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8046       45880 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8047       45880 :         AssignDumpId(&ruleinfo[i].dobj);
    8048       45880 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8049       45880 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8050       45880 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8051       45880 :         if (ruleinfo[i].ruletable == NULL)
    8052           0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8053             :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8054       45880 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8055       45880 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8056       45880 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8057       45880 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8058       45880 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8059       45880 :         if (ruleinfo[i].ruletable)
    8060             :         {
    8061             :             /*
    8062             :              * If the table is a view or materialized view, force its ON
    8063             :              * SELECT rule to be sorted before the view itself --- this
    8064             :              * ensures that any dependencies for the rule affect the table's
    8065             :              * positioning. Other rules are forced to appear after their
    8066             :              * table.
    8067             :              */
    8068       45880 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8069        1184 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8070       45550 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8071             :             {
    8072       44882 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8073       44882 :                                     ruleinfo[i].dobj.dumpId);
    8074             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8075       44882 :                 ruleinfo[i].separate = false;
    8076             :             }
    8077             :             else
    8078             :             {
    8079         998 :                 addObjectDependency(&ruleinfo[i].dobj,
    8080         998 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8081         998 :                 ruleinfo[i].separate = true;
    8082             :             }
    8083             :         }
    8084             :         else
    8085           0 :             ruleinfo[i].separate = true;
    8086             :     }
    8087             : 
    8088         304 :     PQclear(res);
    8089             : 
    8090         304 :     destroyPQExpBuffer(query);
    8091             : 
    8092         304 :     return ruleinfo;
    8093             : }
    8094             : 
    8095             : /*
    8096             :  * getTriggers
    8097             :  *    get information about every trigger on a dumpable table
    8098             :  *
    8099             :  * Note: trigger data is not returned directly to the caller, but it
    8100             :  * does get entered into the DumpableObject tables.
    8101             :  */
    8102             : void
    8103         304 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8104             : {
    8105         304 :     PQExpBuffer query = createPQExpBuffer();
    8106         304 :     PQExpBuffer tbloids = createPQExpBuffer();
    8107             :     PGresult   *res;
    8108             :     int         ntups;
    8109             :     int         curtblindx;
    8110             :     TriggerInfo *tginfo;
    8111             :     int         i_tableoid,
    8112             :                 i_oid,
    8113             :                 i_tgrelid,
    8114             :                 i_tgname,
    8115             :                 i_tgenabled,
    8116             :                 i_tgispartition,
    8117             :                 i_tgdef;
    8118             : 
    8119             :     /*
    8120             :      * We want to perform just one query against pg_trigger.  However, we
    8121             :      * mustn't try to select every row of the catalog and then sort it out on
    8122             :      * the client side, because some of the server-side functions we need
    8123             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8124             :      * build an array of the OIDs of tables we care about (and now have lock
    8125             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8126             :      */
    8127         304 :     appendPQExpBufferChar(tbloids, '{');
    8128       77210 :     for (int i = 0; i < numTables; i++)
    8129             :     {
    8130       76906 :         TableInfo  *tbinfo = &tblinfo[i];
    8131             : 
    8132       76906 :         if (!tbinfo->hastriggers ||
    8133        1778 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8134       75244 :             continue;
    8135             : 
    8136             :         /* OK, we need info for this table */
    8137        1662 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8138        1564 :             appendPQExpBufferChar(tbloids, ',');
    8139        1662 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8140             :     }
    8141         304 :     appendPQExpBufferChar(tbloids, '}');
    8142             : 
    8143         304 :     if (fout->remoteVersion >= 150000)
    8144             :     {
    8145             :         /*
    8146             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8147             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8148             :          * under-parenthesization.
    8149             :          *
    8150             :          * NB: We need to see partition triggers in case the tgenabled flag
    8151             :          * has been changed from the parent.
    8152             :          */
    8153         304 :         appendPQExpBuffer(query,
    8154             :                           "SELECT t.tgrelid, t.tgname, "
    8155             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8156             :                           "t.tgenabled, t.tableoid, t.oid, "
    8157             :                           "t.tgparentid <> 0 AS tgispartition\n"
    8158             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8159             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8160             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8161             :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8162             :                           "OR t.tgenabled != u.tgenabled) "
    8163             :                           "ORDER BY t.tgrelid, t.tgname",
    8164             :                           tbloids->data);
    8165             :     }
    8166           0 :     else if (fout->remoteVersion >= 130000)
    8167             :     {
    8168             :         /*
    8169             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8170             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8171             :          * under-parenthesization.
    8172             :          *
    8173             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8174             :          * tgenabled flag has been changed from the parent.
    8175             :          */
    8176           0 :         appendPQExpBuffer(query,
    8177             :                           "SELECT t.tgrelid, t.tgname, "
    8178             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8179             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8180             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8181             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8182             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8183             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8184             :                           "ORDER BY t.tgrelid, t.tgname",
    8185             :                           tbloids->data);
    8186             :     }
    8187           0 :     else if (fout->remoteVersion >= 110000)
    8188             :     {
    8189             :         /*
    8190             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8191             :          * tgenabled flag has been changed from the parent. No tgparentid in
    8192             :          * version 11-12, so we have to match them via pg_depend.
    8193             :          *
    8194             :          * See above about pretty=true in pg_get_triggerdef.
    8195             :          */
    8196           0 :         appendPQExpBuffer(query,
    8197             :                           "SELECT t.tgrelid, t.tgname, "
    8198             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8199             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8200             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8201             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8202             :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8203             :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8204             :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8205             :                           " d.objid = t.oid "
    8206             :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8207             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8208             :                           "ORDER BY t.tgrelid, t.tgname",
    8209             :                           tbloids->data);
    8210             :     }
    8211             :     else
    8212             :     {
    8213             :         /* See above about pretty=true in pg_get_triggerdef */
    8214           0 :         appendPQExpBuffer(query,
    8215             :                           "SELECT t.tgrelid, t.tgname, "
    8216             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8217             :                           "t.tgenabled, false as tgispartition, "
    8218             :                           "t.tableoid, t.oid "
    8219             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8220             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8221             :                           "WHERE NOT tgisinternal "
    8222             :                           "ORDER BY t.tgrelid, t.tgname",
    8223             :                           tbloids->data);
    8224             :     }
    8225             : 
    8226         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8227             : 
    8228         304 :     ntups = PQntuples(res);
    8229             : 
    8230         304 :     i_tableoid = PQfnumber(res, "tableoid");
    8231         304 :     i_oid = PQfnumber(res, "oid");
    8232         304 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8233         304 :     i_tgname = PQfnumber(res, "tgname");
    8234         304 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8235         304 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8236         304 :     i_tgdef = PQfnumber(res, "tgdef");
    8237             : 
    8238         304 :     tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    8239             : 
    8240             :     /*
    8241             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8242             :      * j is handled by the inner loop.
    8243             :      */
    8244         304 :     curtblindx = -1;
    8245         886 :     for (int j = 0; j < ntups;)
    8246             :     {
    8247         582 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8248         582 :         TableInfo  *tbinfo = NULL;
    8249             :         int         numtrigs;
    8250             : 
    8251             :         /* Count rows for this table */
    8252         986 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8253         888 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8254         484 :                 break;
    8255             : 
    8256             :         /*
    8257             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8258             :          * order.
    8259             :          */
    8260       29950 :         while (++curtblindx < numTables)
    8261             :         {
    8262       29950 :             tbinfo = &tblinfo[curtblindx];
    8263       29950 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8264         582 :                 break;
    8265             :         }
    8266         582 :         if (curtblindx >= numTables)
    8267           0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8268             : 
    8269             :         /* Save data for this table */
    8270         582 :         tbinfo->triggers = tginfo + j;
    8271         582 :         tbinfo->numTriggers = numtrigs;
    8272             : 
    8273        1568 :         for (int c = 0; c < numtrigs; c++, j++)
    8274             :         {
    8275         986 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8276         986 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8277         986 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8278         986 :             AssignDumpId(&tginfo[j].dobj);
    8279         986 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8280         986 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8281         986 :             tginfo[j].tgtable = tbinfo;
    8282         986 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8283         986 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8284         986 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8285             :         }
    8286             :     }
    8287             : 
    8288         304 :     PQclear(res);
    8289             : 
    8290         304 :     destroyPQExpBuffer(query);
    8291         304 :     destroyPQExpBuffer(tbloids);
    8292         304 : }
    8293             : 
    8294             : /*
    8295             :  * getEventTriggers
    8296             :  *    get information about event triggers
    8297             :  */
    8298             : EventTriggerInfo *
    8299         304 : getEventTriggers(Archive *fout, int *numEventTriggers)
    8300             : {
    8301             :     int         i;
    8302             :     PQExpBuffer query;
    8303             :     PGresult   *res;
    8304             :     EventTriggerInfo *evtinfo;
    8305             :     int         i_tableoid,
    8306             :                 i_oid,
    8307             :                 i_evtname,
    8308             :                 i_evtevent,
    8309             :                 i_evtowner,
    8310             :                 i_evttags,
    8311             :                 i_evtfname,
    8312             :                 i_evtenabled;
    8313             :     int         ntups;
    8314             : 
    8315             :     /* Before 9.3, there are no event triggers */
    8316         304 :     if (fout->remoteVersion < 90300)
    8317             :     {
    8318           0 :         *numEventTriggers = 0;
    8319           0 :         return NULL;
    8320             :     }
    8321             : 
    8322         304 :     query = createPQExpBuffer();
    8323             : 
    8324         304 :     appendPQExpBufferStr(query,
    8325             :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8326             :                          "evtevent, evtowner, "
    8327             :                          "array_to_string(array("
    8328             :                          "select quote_literal(x) "
    8329             :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8330             :                          "e.evtfoid::regproc as evtfname "
    8331             :                          "FROM pg_event_trigger e "
    8332             :                          "ORDER BY e.oid");
    8333             : 
    8334         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8335             : 
    8336         304 :     ntups = PQntuples(res);
    8337             : 
    8338         304 :     *numEventTriggers = ntups;
    8339             : 
    8340         304 :     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    8341             : 
    8342         304 :     i_tableoid = PQfnumber(res, "tableoid");
    8343         304 :     i_oid = PQfnumber(res, "oid");
    8344         304 :     i_evtname = PQfnumber(res, "evtname");
    8345         304 :     i_evtevent = PQfnumber(res, "evtevent");
    8346         304 :     i_evtowner = PQfnumber(res, "evtowner");
    8347         304 :     i_evttags = PQfnumber(res, "evttags");
    8348         304 :     i_evtfname = PQfnumber(res, "evtfname");
    8349         304 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8350             : 
    8351         400 :     for (i = 0; i < ntups; i++)
    8352             :     {
    8353          96 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8354          96 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8355          96 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8356          96 :         AssignDumpId(&evtinfo[i].dobj);
    8357          96 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8358          96 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8359          96 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8360          96 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8361          96 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8362          96 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8363          96 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8364             : 
    8365             :         /* Decide whether we want to dump it */
    8366          96 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8367             :     }
    8368             : 
    8369         304 :     PQclear(res);
    8370             : 
    8371         304 :     destroyPQExpBuffer(query);
    8372             : 
    8373         304 :     return evtinfo;
    8374             : }
    8375             : 
    8376             : /*
    8377             :  * getProcLangs
    8378             :  *    get basic information about every procedural language in the system
    8379             :  *
    8380             :  * numProcLangs is set to the number of langs read in
    8381             :  *
    8382             :  * NB: this must run after getFuncs() because we assume we can do
    8383             :  * findFuncByOid().
    8384             :  */
    8385             : ProcLangInfo *
    8386         304 : getProcLangs(Archive *fout, int *numProcLangs)
    8387             : {
    8388             :     PGresult   *res;
    8389             :     int         ntups;
    8390             :     int         i;
    8391         304 :     PQExpBuffer query = createPQExpBuffer();
    8392             :     ProcLangInfo *planginfo;
    8393             :     int         i_tableoid;
    8394             :     int         i_oid;
    8395             :     int         i_lanname;
    8396             :     int         i_lanpltrusted;
    8397             :     int         i_lanplcallfoid;
    8398             :     int         i_laninline;
    8399             :     int         i_lanvalidator;
    8400             :     int         i_lanacl;
    8401             :     int         i_acldefault;
    8402             :     int         i_lanowner;
    8403             : 
    8404         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8405             :                          "lanname, lanpltrusted, lanplcallfoid, "
    8406             :                          "laninline, lanvalidator, "
    8407             :                          "lanacl, "
    8408             :                          "acldefault('l', lanowner) AS acldefault, "
    8409             :                          "lanowner "
    8410             :                          "FROM pg_language "
    8411             :                          "WHERE lanispl "
    8412             :                          "ORDER BY oid");
    8413             : 
    8414         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8415             : 
    8416         304 :     ntups = PQntuples(res);
    8417             : 
    8418         304 :     *numProcLangs = ntups;
    8419             : 
    8420         304 :     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    8421             : 
    8422         304 :     i_tableoid = PQfnumber(res, "tableoid");
    8423         304 :     i_oid = PQfnumber(res, "oid");
    8424         304 :     i_lanname = PQfnumber(res, "lanname");
    8425         304 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    8426         304 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    8427         304 :     i_laninline = PQfnumber(res, "laninline");
    8428         304 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    8429         304 :     i_lanacl = PQfnumber(res, "lanacl");
    8430         304 :     i_acldefault = PQfnumber(res, "acldefault");
    8431         304 :     i_lanowner = PQfnumber(res, "lanowner");
    8432             : 
    8433         694 :     for (i = 0; i < ntups; i++)
    8434             :     {
    8435         390 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8436         390 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8437         390 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8438         390 :         AssignDumpId(&planginfo[i].dobj);
    8439             : 
    8440         390 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8441         390 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8442         390 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    8443         390 :         planginfo[i].dacl.privtype = 0;
    8444         390 :         planginfo[i].dacl.initprivs = NULL;
    8445         390 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8446         390 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8447         390 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8448         390 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8449         390 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    8450             : 
    8451             :         /* Decide whether we want to dump it */
    8452         390 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8453             : 
    8454             :         /* Mark whether language has an ACL */
    8455         390 :         if (!PQgetisnull(res, i, i_lanacl))
    8456          86 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    8457             :     }
    8458             : 
    8459         304 :     PQclear(res);
    8460             : 
    8461         304 :     destroyPQExpBuffer(query);
    8462             : 
    8463         304 :     return planginfo;
    8464             : }
    8465             : 
    8466             : /*
    8467             :  * getCasts
    8468             :  *    get basic information about most casts in the system
    8469             :  *
    8470             :  * numCasts is set to the number of casts read in
    8471             :  *
    8472             :  * Skip casts from a range to its multirange, since we'll create those
    8473             :  * automatically.
    8474             :  */
    8475             : CastInfo *
    8476         304 : getCasts(Archive *fout, int *numCasts)
    8477             : {
    8478             :     PGresult   *res;
    8479             :     int         ntups;
    8480             :     int         i;
    8481         304 :     PQExpBuffer query = createPQExpBuffer();
    8482             :     CastInfo   *castinfo;
    8483             :     int         i_tableoid;
    8484             :     int         i_oid;
    8485             :     int         i_castsource;
    8486             :     int         i_casttarget;
    8487             :     int         i_castfunc;
    8488             :     int         i_castcontext;
    8489             :     int         i_castmethod;
    8490             : 
    8491         304 :     if (fout->remoteVersion >= 140000)
    8492             :     {
    8493         304 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8494             :                              "castsource, casttarget, castfunc, castcontext, "
    8495             :                              "castmethod "
    8496             :                              "FROM pg_cast c "
    8497             :                              "WHERE NOT EXISTS ( "
    8498             :                              "SELECT 1 FROM pg_range r "
    8499             :                              "WHERE c.castsource = r.rngtypid "
    8500             :                              "AND c.casttarget = r.rngmultitypid "
    8501             :                              ") "
    8502             :                              "ORDER BY 3,4");
    8503             :     }
    8504             :     else
    8505             :     {
    8506           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8507             :                              "castsource, casttarget, castfunc, castcontext, "
    8508             :                              "castmethod "
    8509             :                              "FROM pg_cast ORDER BY 3,4");
    8510             :     }
    8511             : 
    8512         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8513             : 
    8514         304 :     ntups = PQntuples(res);
    8515             : 
    8516         304 :     *numCasts = ntups;
    8517             : 
    8518         304 :     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    8519             : 
    8520         304 :     i_tableoid = PQfnumber(res, "tableoid");
    8521         304 :     i_oid = PQfnumber(res, "oid");
    8522         304 :     i_castsource = PQfnumber(res, "castsource");
    8523         304 :     i_casttarget = PQfnumber(res, "casttarget");
    8524         304 :     i_castfunc = PQfnumber(res, "castfunc");
    8525         304 :     i_castcontext = PQfnumber(res, "castcontext");
    8526         304 :     i_castmethod = PQfnumber(res, "castmethod");
    8527             : 
    8528       68242 :     for (i = 0; i < ntups; i++)
    8529             :     {
    8530             :         PQExpBufferData namebuf;
    8531             :         TypeInfo   *sTypeInfo;
    8532             :         TypeInfo   *tTypeInfo;
    8533             : 
    8534       67938 :         castinfo[i].dobj.objType = DO_CAST;
    8535       67938 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8536       67938 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8537       67938 :         AssignDumpId(&castinfo[i].dobj);
    8538       67938 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    8539       67938 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    8540       67938 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    8541       67938 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    8542       67938 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    8543             : 
    8544             :         /*
    8545             :          * Try to name cast as concatenation of typnames.  This is only used
    8546             :          * for purposes of sorting.  If we fail to find either type, the name
    8547             :          * will be an empty string.
    8548             :          */
    8549       67938 :         initPQExpBuffer(&namebuf);
    8550       67938 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    8551       67938 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    8552       67938 :         if (sTypeInfo && tTypeInfo)
    8553       67938 :             appendPQExpBuffer(&namebuf, "%s %s",
    8554             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    8555       67938 :         castinfo[i].dobj.name = namebuf.data;
    8556             : 
    8557             :         /* Decide whether we want to dump it */
    8558       67938 :         selectDumpableCast(&(castinfo[i]), fout);
    8559             :     }
    8560             : 
    8561         304 :     PQclear(res);
    8562             : 
    8563         304 :     destroyPQExpBuffer(query);
    8564             : 
    8565         304 :     return castinfo;
    8566             : }
    8567             : 
    8568             : static char *
    8569         170 : get_language_name(Archive *fout, Oid langid)
    8570             : {
    8571             :     PQExpBuffer query;
    8572             :     PGresult   *res;
    8573             :     char       *lanname;
    8574             : 
    8575         170 :     query = createPQExpBuffer();
    8576         170 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    8577         170 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    8578         170 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    8579         170 :     destroyPQExpBuffer(query);
    8580         170 :     PQclear(res);
    8581             : 
    8582         170 :     return lanname;
    8583             : }
    8584             : 
    8585             : /*
    8586             :  * getTransforms
    8587             :  *    get basic information about every transform in the system
    8588             :  *
    8589             :  * numTransforms is set to the number of transforms read in
    8590             :  */
    8591             : TransformInfo *
    8592         304 : getTransforms(Archive *fout, int *numTransforms)
    8593             : {
    8594             :     PGresult   *res;
    8595             :     int         ntups;
    8596             :     int         i;
    8597             :     PQExpBuffer query;
    8598             :     TransformInfo *transforminfo;
    8599             :     int         i_tableoid;
    8600             :     int         i_oid;
    8601             :     int         i_trftype;
    8602             :     int         i_trflang;
    8603             :     int         i_trffromsql;
    8604             :     int         i_trftosql;
    8605             : 
    8606             :     /* Transforms didn't exist pre-9.5 */
    8607         304 :     if (fout->remoteVersion < 90500)
    8608             :     {
    8609           0 :         *numTransforms = 0;
    8610           0 :         return NULL;
    8611             :     }
    8612             : 
    8613         304 :     query = createPQExpBuffer();
    8614             : 
    8615         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8616             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    8617             :                          "FROM pg_transform "
    8618             :                          "ORDER BY 3,4");
    8619             : 
    8620         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8621             : 
    8622         304 :     ntups = PQntuples(res);
    8623             : 
    8624         304 :     *numTransforms = ntups;
    8625             : 
    8626         304 :     transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    8627             : 
    8628         304 :     i_tableoid = PQfnumber(res, "tableoid");
    8629         304 :     i_oid = PQfnumber(res, "oid");
    8630         304 :     i_trftype = PQfnumber(res, "trftype");
    8631         304 :     i_trflang = PQfnumber(res, "trflang");
    8632         304 :     i_trffromsql = PQfnumber(res, "trffromsql");
    8633         304 :     i_trftosql = PQfnumber(res, "trftosql");
    8634             : 
    8635         400 :     for (i = 0; i < ntups; i++)
    8636             :     {
    8637             :         PQExpBufferData namebuf;
    8638             :         TypeInfo   *typeInfo;
    8639             :         char       *lanname;
    8640             : 
    8641          96 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    8642          96 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8643          96 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8644          96 :         AssignDumpId(&transforminfo[i].dobj);
    8645          96 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    8646          96 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    8647          96 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    8648          96 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    8649             : 
    8650             :         /*
    8651             :          * Try to name transform as concatenation of type and language name.
    8652             :          * This is only used for purposes of sorting.  If we fail to find
    8653             :          * either, the name will be an empty string.
    8654             :          */
    8655          96 :         initPQExpBuffer(&namebuf);
    8656          96 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    8657          96 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    8658          96 :         if (typeInfo && lanname)
    8659          96 :             appendPQExpBuffer(&namebuf, "%s %s",
    8660             :                               typeInfo->dobj.name, lanname);
    8661          96 :         transforminfo[i].dobj.name = namebuf.data;
    8662          96 :         free(lanname);
    8663             : 
    8664             :         /* Decide whether we want to dump it */
    8665          96 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    8666             :     }
    8667             : 
    8668         304 :     PQclear(res);
    8669             : 
    8670         304 :     destroyPQExpBuffer(query);
    8671             : 
    8672         304 :     return transforminfo;
    8673             : }
    8674             : 
    8675             : /*
    8676             :  * getTableAttrs -
    8677             :  *    for each interesting table, read info about its attributes
    8678             :  *    (names, types, default values, CHECK constraints, etc)
    8679             :  *
    8680             :  *  modifies tblinfo
    8681             :  */
    8682             : void
    8683         304 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    8684             : {
    8685         304 :     DumpOptions *dopt = fout->dopt;
    8686         304 :     PQExpBuffer q = createPQExpBuffer();
    8687         304 :     PQExpBuffer tbloids = createPQExpBuffer();
    8688         304 :     PQExpBuffer checkoids = createPQExpBuffer();
    8689             :     PGresult   *res;
    8690             :     int         ntups;
    8691             :     int         curtblindx;
    8692             :     int         i_attrelid;
    8693             :     int         i_attnum;
    8694             :     int         i_attname;
    8695             :     int         i_atttypname;
    8696             :     int         i_attstattarget;
    8697             :     int         i_attstorage;
    8698             :     int         i_typstorage;
    8699             :     int         i_attidentity;
    8700             :     int         i_attgenerated;
    8701             :     int         i_attisdropped;
    8702             :     int         i_attlen;
    8703             :     int         i_attalign;
    8704             :     int         i_attislocal;
    8705             :     int         i_notnull_name;
    8706             :     int         i_notnull_noinherit;
    8707             :     int         i_notnull_is_pk;
    8708             :     int         i_notnull_inh;
    8709             :     int         i_attoptions;
    8710             :     int         i_attcollation;
    8711             :     int         i_attcompression;
    8712             :     int         i_attfdwoptions;
    8713             :     int         i_attmissingval;
    8714             :     int         i_atthasdef;
    8715             : 
    8716             :     /*
    8717             :      * We want to perform just one query against pg_attribute, and then just
    8718             :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    8719             :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    8720             :      * mustn't try to select every row of those catalogs and then sort it out
    8721             :      * on the client side, because some of the server-side functions we need
    8722             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8723             :      * build an array of the OIDs of tables we care about (and now have lock
    8724             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8725             :      */
    8726         304 :     appendPQExpBufferChar(tbloids, '{');
    8727         304 :     appendPQExpBufferChar(checkoids, '{');
    8728       77210 :     for (int i = 0; i < numTables; i++)
    8729             :     {
    8730       76906 :         TableInfo  *tbinfo = &tblinfo[i];
    8731             : 
    8732             :         /* Don't bother to collect info for sequences */
    8733       76906 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    8734         982 :             continue;
    8735             : 
    8736             :         /* Don't bother with uninteresting tables, either */
    8737       75924 :         if (!tbinfo->interesting)
    8738       65064 :             continue;
    8739             : 
    8740             :         /* OK, we need info for this table */
    8741       10860 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8742       10660 :             appendPQExpBufferChar(tbloids, ',');
    8743       10860 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8744             : 
    8745       10860 :         if (tbinfo->ncheck > 0)
    8746             :         {
    8747             :             /* Also make a list of the ones with check constraints */
    8748         884 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    8749         752 :                 appendPQExpBufferChar(checkoids, ',');
    8750         884 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    8751             :         }
    8752             :     }
    8753         304 :     appendPQExpBufferChar(tbloids, '}');
    8754         304 :     appendPQExpBufferChar(checkoids, '}');
    8755             : 
    8756             :     /*
    8757             :      * Find all the user attributes and their types.
    8758             :      *
    8759             :      * Since we only want to dump COLLATE clauses for attributes whose
    8760             :      * collation is different from their type's default, we use a CASE here to
    8761             :      * suppress uninteresting attcollations cheaply.
    8762             :      */
    8763         304 :     appendPQExpBufferStr(q,
    8764             :                          "SELECT\n"
    8765             :                          "a.attrelid,\n"
    8766             :                          "a.attnum,\n"
    8767             :                          "a.attname,\n"
    8768             :                          "a.attstattarget,\n"
    8769             :                          "a.attstorage,\n"
    8770             :                          "t.typstorage,\n"
    8771             :                          "a.atthasdef,\n"
    8772             :                          "a.attisdropped,\n"
    8773             :                          "a.attlen,\n"
    8774             :                          "a.attalign,\n"
    8775             :                          "a.attislocal,\n"
    8776             :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    8777             :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    8778             :                          "CASE WHEN a.attcollation <> t.typcollation "
    8779             :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    8780             :                          "pg_catalog.array_to_string(ARRAY("
    8781             :                          "SELECT pg_catalog.quote_ident(option_name) || "
    8782             :                          "' ' || pg_catalog.quote_literal(option_value) "
    8783             :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    8784             :                          "ORDER BY option_name"
    8785             :                          "), E',\n    ') AS attfdwoptions,\n");
    8786             : 
    8787             :     /*
    8788             :      * Find out any NOT NULL markings for each column.  In 17 and up we read
    8789             :      * pg_constraint to obtain the constraint name.  notnull_noinherit is set
    8790             :      * according to the NO INHERIT property.  For versions prior to 17, we
    8791             :      * store an empty string as the name when a constraint is marked as
    8792             :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    8793             :      * without a name); also, such cases are never NO INHERIT.
    8794             :      *
    8795             :      * We track in notnull_inh whether the constraint was defined directly in
    8796             :      * this table or via an ancestor, for binary upgrade.
    8797             :      *
    8798             :      * Lastly, we need to know if the PK for the table involves each column;
    8799             :      * for columns that are there we need a NOT NULL marking even if there's
    8800             :      * no explicit constraint, to avoid the table having to be scanned for
    8801             :      * NULLs after the data is loaded when the PK is created, later in the
    8802             :      * dump; for this case we add throwaway constraints that are dropped once
    8803             :      * the PK is created.
    8804             :      *
    8805             :      * Another complication arises from columns that have attnotnull set, but
    8806             :      * for which no corresponding not-null nor PK constraint exists.  This can
    8807             :      * happen if, for example, a primary key is dropped indirectly -- say,
    8808             :      * because one of its columns is dropped.  This is an irregular condition,
    8809             :      * so we don't work hard to preserve it, and instead act as though an
    8810             :      * unnamed not-null constraint exists.
    8811             :      */
    8812         304 :     if (fout->remoteVersion >= 170000)
    8813         304 :         appendPQExpBufferStr(q,
    8814             :                              "CASE WHEN co.conname IS NOT NULL THEN co.conname "
    8815             :                              "  WHEN a.attnotnull AND copk.conname IS NULL THEN '' ELSE NULL END AS notnull_name,\n"
    8816             :                              "CASE WHEN co.conname IS NOT NULL THEN co.connoinherit "
    8817             :                              "  WHEN a.attnotnull THEN false ELSE NULL END AS notnull_noinherit,\n"
    8818             :                              "copk.conname IS NOT NULL as notnull_is_pk,\n"
    8819             :                              "CASE WHEN co.conname IS NOT NULL THEN "
    8820             :                              "  coalesce(NOT co.conislocal, true) "
    8821             :                              "ELSE false END as notnull_inh,\n");
    8822             :     else
    8823           0 :         appendPQExpBufferStr(q,
    8824             :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    8825             :                              "false AS notnull_noinherit,\n"
    8826             :                              "copk.conname IS NOT NULL AS notnull_is_pk,\n"
    8827             :                              "NOT a.attislocal AS notnull_inh,\n");
    8828             : 
    8829         304 :     if (fout->remoteVersion >= 140000)
    8830         304 :         appendPQExpBufferStr(q,
    8831             :                              "a.attcompression AS attcompression,\n");
    8832             :     else
    8833           0 :         appendPQExpBufferStr(q,
    8834             :                              "'' AS attcompression,\n");
    8835             : 
    8836         304 :     if (fout->remoteVersion >= 100000)
    8837         304 :         appendPQExpBufferStr(q,
    8838             :                              "a.attidentity,\n");
    8839             :     else
    8840           0 :         appendPQExpBufferStr(q,
    8841             :                              "'' AS attidentity,\n");
    8842             : 
    8843         304 :     if (fout->remoteVersion >= 110000)
    8844         304 :         appendPQExpBufferStr(q,
    8845             :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    8846             :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    8847             :     else
    8848           0 :         appendPQExpBufferStr(q,
    8849             :                              "NULL AS attmissingval,\n");
    8850             : 
    8851         304 :     if (fout->remoteVersion >= 120000)
    8852         304 :         appendPQExpBufferStr(q,
    8853             :                              "a.attgenerated\n");
    8854             :     else
    8855           0 :         appendPQExpBufferStr(q,
    8856             :                              "'' AS attgenerated\n");
    8857             : 
    8858             :     /* need left join to pg_type to not fail on dropped columns ... */
    8859         304 :     appendPQExpBuffer(q,
    8860             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8861             :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    8862             :                       "LEFT JOIN pg_catalog.pg_type t "
    8863             :                       "ON (a.atttypid = t.oid)\n",
    8864             :                       tbloids->data);
    8865             : 
    8866             :     /*
    8867             :      * In versions 17 and up, we need pg_constraint for explicit NOT NULL
    8868             :      * entries.  Also, we need to know if the NOT NULL for each column is
    8869             :      * backing a primary key.
    8870             :      */
    8871         304 :     if (fout->remoteVersion >= 170000)
    8872         304 :         appendPQExpBufferStr(q,
    8873             :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    8874             :                              "(a.attrelid = co.conrelid\n"
    8875             :                              "   AND co.contype = 'n' AND "
    8876             :                              "co.conkey = array[a.attnum])\n");
    8877             : 
    8878         304 :     appendPQExpBufferStr(q,
    8879             :                          "LEFT JOIN pg_catalog.pg_constraint copk ON "
    8880             :                          "(copk.conrelid = src.tbloid\n"
    8881             :                          "   AND copk.contype = 'p' AND "
    8882             :                          "copk.conkey @> array[a.attnum])\n"
    8883             :                          "WHERE a.attnum > 0::pg_catalog.int2\n"
    8884             :                          "ORDER BY a.attrelid, a.attnum");
    8885             : 
    8886         304 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    8887             : 
    8888         304 :     ntups = PQntuples(res);
    8889             : 
    8890         304 :     i_attrelid = PQfnumber(res, "attrelid");
    8891         304 :     i_attnum = PQfnumber(res, "attnum");
    8892         304 :     i_attname = PQfnumber(res, "attname");
    8893         304 :     i_atttypname = PQfnumber(res, "atttypname");
    8894         304 :     i_attstattarget = PQfnumber(res, "attstattarget");
    8895         304 :     i_attstorage = PQfnumber(res, "attstorage");
    8896         304 :     i_typstorage = PQfnumber(res, "typstorage");
    8897         304 :     i_attidentity = PQfnumber(res, "attidentity");
    8898         304 :     i_attgenerated = PQfnumber(res, "attgenerated");
    8899         304 :     i_attisdropped = PQfnumber(res, "attisdropped");
    8900         304 :     i_attlen = PQfnumber(res, "attlen");
    8901         304 :     i_attalign = PQfnumber(res, "attalign");
    8902         304 :     i_attislocal = PQfnumber(res, "attislocal");
    8903         304 :     i_notnull_name = PQfnumber(res, "notnull_name");
    8904         304 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    8905         304 :     i_notnull_is_pk = PQfnumber(res, "notnull_is_pk");
    8906         304 :     i_notnull_inh = PQfnumber(res, "notnull_inh");
    8907         304 :     i_attoptions = PQfnumber(res, "attoptions");
    8908         304 :     i_attcollation = PQfnumber(res, "attcollation");
    8909         304 :     i_attcompression = PQfnumber(res, "attcompression");
    8910         304 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    8911         304 :     i_attmissingval = PQfnumber(res, "attmissingval");
    8912         304 :     i_atthasdef = PQfnumber(res, "atthasdef");
    8913             : 
    8914             :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    8915         304 :     resetPQExpBuffer(tbloids);
    8916         304 :     appendPQExpBufferChar(tbloids, '{');
    8917             : 
    8918             :     /*
    8919             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8920             :      * r is handled by the inner loop.
    8921             :      */
    8922         304 :     curtblindx = -1;
    8923       10910 :     for (int r = 0; r < ntups;)
    8924             :     {
    8925       10606 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    8926       10606 :         TableInfo  *tbinfo = NULL;
    8927             :         int         numatts;
    8928             :         bool        hasdefaults;
    8929             :         int         notnullcount;
    8930             : 
    8931             :         /* Count rows for this table */
    8932       39122 :         for (numatts = 1; numatts < ntups - r; numatts++)
    8933       38928 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    8934       10412 :                 break;
    8935             : 
    8936             :         /*
    8937             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8938             :          * order.
    8939             :          */
    8940       53110 :         while (++curtblindx < numTables)
    8941             :         {
    8942       53110 :             tbinfo = &tblinfo[curtblindx];
    8943       53110 :             if (tbinfo->dobj.catId.oid == attrelid)
    8944       10606 :                 break;
    8945             :         }
    8946       10606 :         if (curtblindx >= numTables)
    8947           0 :             pg_fatal("unrecognized table OID %u", attrelid);
    8948             :         /* cross-check that we only got requested tables */
    8949       10606 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    8950       10606 :             !tbinfo->interesting)
    8951           0 :             pg_fatal("unexpected column data for table \"%s\"",
    8952             :                      tbinfo->dobj.name);
    8953             : 
    8954       10606 :         notnullcount = 0;
    8955             : 
    8956             :         /* Save data for this table */
    8957       10606 :         tbinfo->numatts = numatts;
    8958       10606 :         tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
    8959       10606 :         tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
    8960       10606 :         tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
    8961       10606 :         tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
    8962       10606 :         tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
    8963       10606 :         tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
    8964       10606 :         tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
    8965       10606 :         tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
    8966       10606 :         tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
    8967       10606 :         tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
    8968       10606 :         tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
    8969       10606 :         tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
    8970       10606 :         tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
    8971       10606 :         tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
    8972       10606 :         tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
    8973       10606 :         tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
    8974       10606 :         tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
    8975       10606 :         tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
    8976       10606 :         tbinfo->notnull_throwaway = (bool *) pg_malloc(numatts * sizeof(bool));
    8977       10606 :         tbinfo->notnull_inh = (bool *) pg_malloc(numatts * sizeof(bool));
    8978       10606 :         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
    8979       10606 :         hasdefaults = false;
    8980             : 
    8981       49728 :         for (int j = 0; j < numatts; j++, r++)
    8982             :         {
    8983       39122 :             bool        use_named_notnull = false;
    8984       39122 :             bool        use_unnamed_notnull = false;
    8985       39122 :             bool        use_throwaway_notnull = false;
    8986             : 
    8987       39122 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
    8988           0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    8989             :                          tbinfo->dobj.name);
    8990       39122 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    8991       39122 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    8992       39122 :             if (PQgetisnull(res, r, i_attstattarget))
    8993       39048 :                 tbinfo->attstattarget[j] = -1;
    8994             :             else
    8995          74 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    8996       39122 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    8997       39122 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    8998       39122 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    8999       39122 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9000       39122 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9001       39122 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9002       39122 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9003       39122 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9004       39122 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9005             : 
    9006             :             /*
    9007             :              * Not-null constraints require a jumping through a few hoops.
    9008             :              * First, if the user has specified a constraint name that's not
    9009             :              * the system-assigned default name, then we need to preserve
    9010             :              * that. But if they haven't, then we don't want to use the
    9011             :              * verbose syntax in the dump output. (Also, in versions prior to
    9012             :              * 17, there was no constraint name at all.)
    9013             :              *
    9014             :              * (XXX Comparing the name this way to a supposed default name is
    9015             :              * a bit of a hack, but it beats having to store a boolean flag in
    9016             :              * pg_constraint just for this, or having to compute the knowledge
    9017             :              * at pg_dump time from the server.)
    9018             :              *
    9019             :              * We also need to know if a column is part of the primary key. In
    9020             :              * that case, we want to mark the column as not-null at table
    9021             :              * creation time, so that the table doesn't have to be scanned to
    9022             :              * check for nulls when the PK is created afterwards; this is
    9023             :              * especially critical during pg_upgrade (where the data would not
    9024             :              * be scanned at all otherwise.)  If the column is part of the PK
    9025             :              * and does not have any other not-null constraint, then we
    9026             :              * fabricate a throwaway constraint name that we later use to
    9027             :              * remove the constraint after the PK has been created.
    9028             :              *
    9029             :              * For inheritance child tables, we don't want to print not-null
    9030             :              * when the constraint was defined at the parent level instead of
    9031             :              * locally.
    9032             :              */
    9033             : 
    9034             :             /*
    9035             :              * We use notnull_inh to suppress unwanted not-null constraints in
    9036             :              * inheritance children, when said constraints come from the
    9037             :              * parent(s).
    9038             :              */
    9039       39122 :             tbinfo->notnull_inh[j] = PQgetvalue(res, r, i_notnull_inh)[0] == 't';
    9040             : 
    9041       39122 :             if (fout->remoteVersion < 170000)
    9042             :             {
    9043           0 :                 if (!PQgetisnull(res, r, i_notnull_name) &&
    9044           0 :                     dopt->binary_upgrade &&
    9045           0 :                     !tbinfo->ispartition &&
    9046           0 :                     tbinfo->notnull_inh[j])
    9047             :                 {
    9048           0 :                     use_named_notnull = true;
    9049             :                     /* XXX should match ChooseConstraintName better */
    9050           0 :                     tbinfo->notnull_constrs[j] =
    9051           0 :                         psprintf("%s_%s_not_null", tbinfo->dobj.name,
    9052           0 :                                  tbinfo->attnames[j]);
    9053             :                 }
    9054           0 :                 else if (PQgetvalue(res, r, i_notnull_is_pk)[0] == 't')
    9055             :                 {
    9056             :                     /*
    9057             :                      * We want this flag to be set for columns of a primary
    9058             :                      * key in which data is going to be loaded by the dump we
    9059             :                      * produce; thus a partitioned table doesn't need it.
    9060             :                      */
    9061           0 :                     if (tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    9062           0 :                         use_throwaway_notnull = true;
    9063             :                 }
    9064           0 :                 else if (!PQgetisnull(res, r, i_notnull_name))
    9065           0 :                     use_unnamed_notnull = true;
    9066             :             }
    9067             :             else
    9068             :             {
    9069       39122 :                 if (!PQgetisnull(res, r, i_notnull_name))
    9070             :                 {
    9071             :                     /*
    9072             :                      * In binary upgrade of inheritance child tables, must
    9073             :                      * have a constraint name that we can UPDATE later.
    9074             :                      */
    9075        3172 :                     if (dopt->binary_upgrade &&
    9076         262 :                         !tbinfo->ispartition &&
    9077         172 :                         tbinfo->notnull_inh[j])
    9078             :                     {
    9079          32 :                         use_named_notnull = true;
    9080          32 :                         tbinfo->notnull_constrs[j] =
    9081          32 :                             pstrdup(PQgetvalue(res, r, i_notnull_name));
    9082             : 
    9083             :                     }
    9084             :                     else
    9085             :                     {
    9086             :                         char       *default_name;
    9087             : 
    9088             :                         /* XXX should match ChooseConstraintName better */
    9089        3140 :                         default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
    9090        3140 :                                                 tbinfo->attnames[j]);
    9091        3140 :                         if (strcmp(default_name,
    9092        3140 :                                    PQgetvalue(res, r, i_notnull_name)) == 0)
    9093        1388 :                             use_unnamed_notnull = true;
    9094             :                         else
    9095             :                         {
    9096        1752 :                             use_named_notnull = true;
    9097        1752 :                             tbinfo->notnull_constrs[j] =
    9098        1752 :                                 pstrdup(PQgetvalue(res, r, i_notnull_name));
    9099             :                         }
    9100             :                     }
    9101             :                 }
    9102       35950 :                 else if (PQgetvalue(res, r, i_notnull_is_pk)[0] == 't')
    9103             :                 {
    9104             :                     /* see above */
    9105        1598 :                     if (tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    9106        1468 :                         use_throwaway_notnull = true;
    9107             :                 }
    9108             :             }
    9109             : 
    9110       39122 :             if (use_unnamed_notnull)
    9111             :             {
    9112        1388 :                 tbinfo->notnull_constrs[j] = "";
    9113        1388 :                 tbinfo->notnull_throwaway[j] = false;
    9114             :             }
    9115       37734 :             else if (use_named_notnull)
    9116             :             {
    9117             :                 /* The name itself has already been determined */
    9118        1784 :                 tbinfo->notnull_throwaway[j] = false;
    9119             :             }
    9120       35950 :             else if (use_throwaway_notnull)
    9121             :             {
    9122             :                 /*
    9123             :                  * Give this constraint a throwaway name.
    9124             :                  */
    9125        2936 :                 tbinfo->notnull_constrs[j] =
    9126        1468 :                     psprintf("pgdump_throwaway_notnull_%d", notnullcount++);
    9127        1468 :                 tbinfo->notnull_throwaway[j] = true;
    9128        1468 :                 tbinfo->notnull_inh[j] = false;
    9129             :             }
    9130             :             else
    9131             :             {
    9132       34482 :                 tbinfo->notnull_constrs[j] = NULL;
    9133       34482 :                 tbinfo->notnull_throwaway[j] = false;
    9134             :             }
    9135             : 
    9136             :             /*
    9137             :              * Throwaway constraints must always be NO INHERIT; otherwise do
    9138             :              * what the catalog says.
    9139             :              */
    9140       76776 :             tbinfo->notnull_noinh[j] = use_throwaway_notnull ||
    9141       37654 :                 PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
    9142             : 
    9143       39122 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9144       39122 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9145       39122 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9146       39122 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9147       39122 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9148       39122 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9149       39122 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9150        1686 :                 hasdefaults = true;
    9151             :         }
    9152             : 
    9153       10606 :         if (hasdefaults)
    9154             :         {
    9155             :             /* Collect OIDs of interesting tables that have defaults */
    9156        1390 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9157        1294 :                 appendPQExpBufferChar(tbloids, ',');
    9158        1390 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9159             :         }
    9160             :     }
    9161             : 
    9162         304 :     PQclear(res);
    9163             : 
    9164             :     /*
    9165             :      * Now get info about column defaults.  This is skipped for a data-only
    9166             :      * dump, as it is only needed for table schemas.
    9167             :      */
    9168         304 :     if (!dopt->dataOnly && tbloids->len > 1)
    9169             :     {
    9170             :         AttrDefInfo *attrdefs;
    9171             :         int         numDefaults;
    9172          88 :         TableInfo  *tbinfo = NULL;
    9173             : 
    9174          88 :         pg_log_info("finding table default expressions");
    9175             : 
    9176          88 :         appendPQExpBufferChar(tbloids, '}');
    9177             : 
    9178          88 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9179             :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9180             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9181             :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9182             :                           "ORDER BY a.adrelid, a.adnum",
    9183             :                           tbloids->data);
    9184             : 
    9185          88 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9186             : 
    9187          88 :         numDefaults = PQntuples(res);
    9188          88 :         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    9189             : 
    9190          88 :         curtblindx = -1;
    9191        1694 :         for (int j = 0; j < numDefaults; j++)
    9192             :         {
    9193        1606 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9194        1606 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9195        1606 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9196        1606 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9197        1606 :             char       *adsrc = PQgetvalue(res, j, 4);
    9198             : 
    9199             :             /*
    9200             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9201             :              * OID order.
    9202             :              */
    9203        1606 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9204             :             {
    9205       29442 :                 while (++curtblindx < numTables)
    9206             :                 {
    9207       29442 :                     tbinfo = &tblinfo[curtblindx];
    9208       29442 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9209        1322 :                         break;
    9210             :                 }
    9211        1322 :                 if (curtblindx >= numTables)
    9212           0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9213             :             }
    9214             : 
    9215        1606 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9216           0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9217             :                          adnum, tbinfo->dobj.name);
    9218             : 
    9219             :             /*
    9220             :              * dropped columns shouldn't have defaults, but just in case,
    9221             :              * ignore 'em
    9222             :              */
    9223        1606 :             if (tbinfo->attisdropped[adnum - 1])
    9224           0 :                 continue;
    9225             : 
    9226        1606 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9227        1606 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9228        1606 :             attrdefs[j].dobj.catId.oid = adoid;
    9229        1606 :             AssignDumpId(&attrdefs[j].dobj);
    9230        1606 :             attrdefs[j].adtable = tbinfo;
    9231        1606 :             attrdefs[j].adnum = adnum;
    9232        1606 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9233             : 
    9234        1606 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9235        1606 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9236             : 
    9237        1606 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9238             : 
    9239             :             /*
    9240             :              * Figure out whether the default/generation expression should be
    9241             :              * dumped as part of the main CREATE TABLE (or similar) command or
    9242             :              * as a separate ALTER TABLE (or similar) command. The preference
    9243             :              * is to put it into the CREATE command, but in some cases that's
    9244             :              * not possible.
    9245             :              */
    9246        1606 :             if (tbinfo->attgenerated[adnum - 1])
    9247             :             {
    9248             :                 /*
    9249             :                  * Column generation expressions cannot be dumped separately,
    9250             :                  * because there is no syntax for it.  By setting separate to
    9251             :                  * false here we prevent the "default" from being processed as
    9252             :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9253             :                  * it as not to be dumped at all, if possible (that is, if it
    9254             :                  * can be inherited from a parent).
    9255             :                  */
    9256         690 :                 attrdefs[j].separate = false;
    9257             :             }
    9258         916 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9259             :             {
    9260             :                 /*
    9261             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9262             :                  * TABLE commands.
    9263             :                  */
    9264          66 :                 attrdefs[j].separate = true;
    9265             :             }
    9266         850 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9267             :             {
    9268             :                 /* column will be suppressed, print default separately */
    9269           8 :                 attrdefs[j].separate = true;
    9270             :             }
    9271             :             else
    9272             :             {
    9273         842 :                 attrdefs[j].separate = false;
    9274             :             }
    9275             : 
    9276        1606 :             if (!attrdefs[j].separate)
    9277             :             {
    9278             :                 /*
    9279             :                  * Mark the default as needing to appear before the table, so
    9280             :                  * that any dependencies it has must be emitted before the
    9281             :                  * CREATE TABLE.  If this is not possible, we'll change to
    9282             :                  * "separate" mode while sorting dependencies.
    9283             :                  */
    9284        1532 :                 addObjectDependency(&tbinfo->dobj,
    9285        1532 :                                     attrdefs[j].dobj.dumpId);
    9286             :             }
    9287             : 
    9288        1606 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9289             :         }
    9290             : 
    9291          88 :         PQclear(res);
    9292             :     }
    9293             : 
    9294             :     /*
    9295             :      * Get info about table CHECK constraints.  This is skipped for a
    9296             :      * data-only dump, as it is only needed for table schemas.
    9297             :      */
    9298         304 :     if (!dopt->dataOnly && checkoids->len > 2)
    9299             :     {
    9300             :         ConstraintInfo *constrs;
    9301             :         int         numConstrs;
    9302             :         int         i_tableoid;
    9303             :         int         i_oid;
    9304             :         int         i_conrelid;
    9305             :         int         i_conname;
    9306             :         int         i_consrc;
    9307             :         int         i_conislocal;
    9308             :         int         i_convalidated;
    9309             : 
    9310         122 :         pg_log_info("finding table check constraints");
    9311             : 
    9312         122 :         resetPQExpBuffer(q);
    9313         122 :         appendPQExpBuffer(q,
    9314             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9315             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9316             :                           "conislocal, convalidated "
    9317             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9318             :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9319             :                           "WHERE contype = 'c' "
    9320             :                           "ORDER BY c.conrelid, c.conname",
    9321             :                           checkoids->data);
    9322             : 
    9323         122 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9324             : 
    9325         122 :         numConstrs = PQntuples(res);
    9326         122 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9327             : 
    9328         122 :         i_tableoid = PQfnumber(res, "tableoid");
    9329         122 :         i_oid = PQfnumber(res, "oid");
    9330         122 :         i_conrelid = PQfnumber(res, "conrelid");
    9331         122 :         i_conname = PQfnumber(res, "conname");
    9332         122 :         i_consrc = PQfnumber(res, "consrc");
    9333         122 :         i_conislocal = PQfnumber(res, "conislocal");
    9334         122 :         i_convalidated = PQfnumber(res, "convalidated");
    9335             : 
    9336             :         /* As above, this loop iterates once per table, not once per row */
    9337         122 :         curtblindx = -1;
    9338         954 :         for (int j = 0; j < numConstrs;)
    9339             :         {
    9340         832 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9341         832 :             TableInfo  *tbinfo = NULL;
    9342             :             int         numcons;
    9343             : 
    9344             :             /* Count rows for this table */
    9345        1096 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9346         974 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9347         710 :                     break;
    9348             : 
    9349             :             /*
    9350             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9351             :              * OID order.
    9352             :              */
    9353       34960 :             while (++curtblindx < numTables)
    9354             :             {
    9355       34960 :                 tbinfo = &tblinfo[curtblindx];
    9356       34960 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9357         832 :                     break;
    9358             :             }
    9359         832 :             if (curtblindx >= numTables)
    9360           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9361             : 
    9362         832 :             if (numcons != tbinfo->ncheck)
    9363             :             {
    9364           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9365             :                                       "expected %d check constraints on table \"%s\" but found %d",
    9366             :                                       tbinfo->ncheck),
    9367             :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9368           0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9369           0 :                 exit_nicely(1);
    9370             :             }
    9371             : 
    9372         832 :             tbinfo->checkexprs = constrs + j;
    9373             : 
    9374        1928 :             for (int c = 0; c < numcons; c++, j++)
    9375             :             {
    9376        1096 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9377             : 
    9378        1096 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9379        1096 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9380        1096 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9381        1096 :                 AssignDumpId(&constrs[j].dobj);
    9382        1096 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9383        1096 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9384        1096 :                 constrs[j].contable = tbinfo;
    9385        1096 :                 constrs[j].condomain = NULL;
    9386        1096 :                 constrs[j].contype = 'c';
    9387        1096 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9388        1096 :                 constrs[j].confrelid = InvalidOid;
    9389        1096 :                 constrs[j].conindex = 0;
    9390        1096 :                 constrs[j].condeferrable = false;
    9391        1096 :                 constrs[j].condeferred = false;
    9392        1096 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9393             : 
    9394             :                 /*
    9395             :                  * An unvalidated constraint needs to be dumped separately, so
    9396             :                  * that potentially-violating existing data is loaded before
    9397             :                  * the constraint.
    9398             :                  */
    9399        1096 :                 constrs[j].separate = !validated;
    9400             : 
    9401        1096 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9402             : 
    9403             :                 /*
    9404             :                  * Mark the constraint as needing to appear before the table
    9405             :                  * --- this is so that any other dependencies of the
    9406             :                  * constraint will be emitted before we try to create the
    9407             :                  * table.  If the constraint is to be dumped separately, it
    9408             :                  * will be dumped after data is loaded anyway, so don't do it.
    9409             :                  * (There's an automatic dependency in the opposite direction
    9410             :                  * anyway, so don't need to add one manually here.)
    9411             :                  */
    9412        1096 :                 if (!constrs[j].separate)
    9413        1026 :                     addObjectDependency(&tbinfo->dobj,
    9414        1026 :                                         constrs[j].dobj.dumpId);
    9415             : 
    9416             :                 /*
    9417             :                  * We will detect later whether the constraint must be split
    9418             :                  * out from the table definition.
    9419             :                  */
    9420             :             }
    9421             :         }
    9422             : 
    9423         122 :         PQclear(res);
    9424             :     }
    9425             : 
    9426         304 :     destroyPQExpBuffer(q);
    9427         304 :     destroyPQExpBuffer(tbloids);
    9428         304 :     destroyPQExpBuffer(checkoids);
    9429         304 : }
    9430             : 
    9431             : /*
    9432             :  * Test whether a column should be printed as part of table's CREATE TABLE.
    9433             :  * Column number is zero-based.
    9434             :  *
    9435             :  * Normally this is always true, but it's false for dropped columns, as well
    9436             :  * as those that were inherited without any local definition.  (If we print
    9437             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
    9438             :  * For partitions, it's always true, because we want the partitions to be
    9439             :  * created independently and ATTACH PARTITION used afterwards.
    9440             :  *
    9441             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
    9442             :  * attisdropped state later, so as to keep control of the physical column
    9443             :  * order.
    9444             :  *
    9445             :  * This function exists because there are scattered nonobvious places that
    9446             :  * must be kept in sync with this decision.
    9447             :  */
    9448             : bool
    9449       70538 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
    9450             : {
    9451       70538 :     if (dopt->binary_upgrade)
    9452       11650 :         return true;
    9453       58888 :     if (tbinfo->attisdropped[colno])
    9454         696 :         return false;
    9455       58192 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
    9456             : }
    9457             : 
    9458             : 
    9459             : /*
    9460             :  * getTSParsers:
    9461             :  *    read all text search parsers in the system catalogs and return them
    9462             :  *    in the TSParserInfo* structure
    9463             :  *
    9464             :  *  numTSParsers is set to the number of parsers read in
    9465             :  */
    9466             : TSParserInfo *
    9467         304 : getTSParsers(Archive *fout, int *numTSParsers)
    9468             : {
    9469             :     PGresult   *res;
    9470             :     int         ntups;
    9471             :     int         i;
    9472             :     PQExpBuffer query;
    9473             :     TSParserInfo *prsinfo;
    9474             :     int         i_tableoid;
    9475             :     int         i_oid;
    9476             :     int         i_prsname;
    9477             :     int         i_prsnamespace;
    9478             :     int         i_prsstart;
    9479             :     int         i_prstoken;
    9480             :     int         i_prsend;
    9481             :     int         i_prsheadline;
    9482             :     int         i_prslextype;
    9483             : 
    9484         304 :     query = createPQExpBuffer();
    9485             : 
    9486             :     /*
    9487             :      * find all text search objects, including builtin ones; we filter out
    9488             :      * system-defined objects at dump-out time.
    9489             :      */
    9490             : 
    9491         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
    9492             :                          "prsstart::oid, prstoken::oid, "
    9493             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
    9494             :                          "FROM pg_ts_parser");
    9495             : 
    9496         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9497             : 
    9498         304 :     ntups = PQntuples(res);
    9499         304 :     *numTSParsers = ntups;
    9500             : 
    9501         304 :     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
    9502             : 
    9503         304 :     i_tableoid = PQfnumber(res, "tableoid");
    9504         304 :     i_oid = PQfnumber(res, "oid");
    9505         304 :     i_prsname = PQfnumber(res, "prsname");
    9506         304 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
    9507         304 :     i_prsstart = PQfnumber(res, "prsstart");
    9508         304 :     i_prstoken = PQfnumber(res, "prstoken");
    9509         304 :     i_prsend = PQfnumber(res, "prsend");
    9510         304 :     i_prsheadline = PQfnumber(res, "prsheadline");
    9511         304 :     i_prslextype = PQfnumber(res, "prslextype");
    9512             : 
    9513         694 :     for (i = 0; i < ntups; i++)
    9514             :     {
    9515         390 :         prsinfo[i].dobj.objType = DO_TSPARSER;
    9516         390 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9517         390 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9518         390 :         AssignDumpId(&prsinfo[i].dobj);
    9519         390 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
    9520         780 :         prsinfo[i].dobj.namespace =
    9521         390 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
    9522         390 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
    9523         390 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
    9524         390 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
    9525         390 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
    9526         390 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
    9527             : 
    9528             :         /* Decide whether we want to dump it */
    9529         390 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
    9530             :     }
    9531             : 
    9532         304 :     PQclear(res);
    9533             : 
    9534         304 :     destroyPQExpBuffer(query);
    9535             : 
    9536         304 :     return prsinfo;
    9537             : }
    9538             : 
    9539             : /*
    9540             :  * getTSDictionaries:
    9541             :  *    read all text search dictionaries in the system catalogs and return them
    9542             :  *    in the TSDictInfo* structure
    9543             :  *
    9544             :  *  numTSDicts is set to the number of dictionaries read in
    9545             :  */
    9546             : TSDictInfo *
    9547         304 : getTSDictionaries(Archive *fout, int *numTSDicts)
    9548             : {
    9549             :     PGresult   *res;
    9550             :     int         ntups;
    9551             :     int         i;
    9552             :     PQExpBuffer query;
    9553             :     TSDictInfo *dictinfo;
    9554             :     int         i_tableoid;
    9555             :     int         i_oid;
    9556             :     int         i_dictname;
    9557             :     int         i_dictnamespace;
    9558             :     int         i_dictowner;
    9559             :     int         i_dicttemplate;
    9560             :     int         i_dictinitoption;
    9561             : 
    9562         304 :     query = createPQExpBuffer();
    9563             : 
    9564         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
    9565             :                          "dictnamespace, dictowner, "
    9566             :                          "dicttemplate, dictinitoption "
    9567             :                          "FROM pg_ts_dict");
    9568             : 
    9569         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9570             : 
    9571         304 :     ntups = PQntuples(res);
    9572         304 :     *numTSDicts = ntups;
    9573             : 
    9574         304 :     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
    9575             : 
    9576         304 :     i_tableoid = PQfnumber(res, "tableoid");
    9577         304 :     i_oid = PQfnumber(res, "oid");
    9578         304 :     i_dictname = PQfnumber(res, "dictname");
    9579         304 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
    9580         304 :     i_dictowner = PQfnumber(res, "dictowner");
    9581         304 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
    9582         304 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
    9583             : 
    9584        9296 :     for (i = 0; i < ntups; i++)
    9585             :     {
    9586        8992 :         dictinfo[i].dobj.objType = DO_TSDICT;
    9587        8992 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9588        8992 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9589        8992 :         AssignDumpId(&dictinfo[i].dobj);
    9590        8992 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
    9591       17984 :         dictinfo[i].dobj.namespace =
    9592        8992 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
    9593        8992 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
    9594        8992 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
    9595        8992 :         if (PQgetisnull(res, i, i_dictinitoption))
    9596         390 :             dictinfo[i].dictinitoption = NULL;
    9597             :         else
    9598        8602 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
    9599             : 
    9600             :         /* Decide whether we want to dump it */
    9601        8992 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
    9602             :     }
    9603             : 
    9604         304 :     PQclear(res);
    9605             : 
    9606         304 :     destroyPQExpBuffer(query);
    9607             : 
    9608         304 :     return dictinfo;
    9609             : }
    9610             : 
    9611             : /*
    9612             :  * getTSTemplates:
    9613             :  *    read all text search templates in the system catalogs and return them
    9614             :  *    in the TSTemplateInfo* structure
    9615             :  *
    9616             :  *  numTSTemplates is set to the number of templates read in
    9617             :  */
    9618             : TSTemplateInfo *
    9619         304 : getTSTemplates(Archive *fout, int *numTSTemplates)
    9620             : {
    9621             :     PGresult   *res;
    9622             :     int         ntups;
    9623             :     int         i;
    9624             :     PQExpBuffer query;
    9625             :     TSTemplateInfo *tmplinfo;
    9626             :     int         i_tableoid;
    9627             :     int         i_oid;
    9628             :     int         i_tmplname;
    9629             :     int         i_tmplnamespace;
    9630             :     int         i_tmplinit;
    9631             :     int         i_tmpllexize;
    9632             : 
    9633         304 :     query = createPQExpBuffer();
    9634             : 
    9635         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
    9636             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
    9637             :                          "FROM pg_ts_template");
    9638             : 
    9639         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9640             : 
    9641         304 :     ntups = PQntuples(res);
    9642         304 :     *numTSTemplates = ntups;
    9643             : 
    9644         304 :     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
    9645             : 
    9646         304 :     i_tableoid = PQfnumber(res, "tableoid");
    9647         304 :     i_oid = PQfnumber(res, "oid");
    9648         304 :     i_tmplname = PQfnumber(res, "tmplname");
    9649         304 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
    9650         304 :     i_tmplinit = PQfnumber(res, "tmplinit");
    9651         304 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
    9652             : 
    9653        1910 :     for (i = 0; i < ntups; i++)
    9654             :     {
    9655        1606 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
    9656        1606 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9657        1606 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9658        1606 :         AssignDumpId(&tmplinfo[i].dobj);
    9659        1606 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
    9660        3212 :         tmplinfo[i].dobj.namespace =
    9661        1606 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
    9662        1606 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
    9663        1606 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
    9664             : 
    9665             :         /* Decide whether we want to dump it */
    9666        1606 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
    9667             :     }
    9668             : 
    9669         304 :     PQclear(res);
    9670             : 
    9671         304 :     destroyPQExpBuffer(query);
    9672             : 
    9673         304 :     return tmplinfo;
    9674             : }
    9675             : 
    9676             : /*
    9677             :  * getTSConfigurations:
    9678             :  *    read all text search configurations in the system catalogs and return
    9679             :  *    them in the TSConfigInfo* structure
    9680             :  *
    9681             :  *  numTSConfigs is set to the number of configurations read in
    9682             :  */
    9683             : TSConfigInfo *
    9684         304 : getTSConfigurations(Archive *fout, int *numTSConfigs)
    9685             : {
    9686             :     PGresult   *res;
    9687             :     int         ntups;
    9688             :     int         i;
    9689             :     PQExpBuffer query;
    9690             :     TSConfigInfo *cfginfo;
    9691             :     int         i_tableoid;
    9692             :     int         i_oid;
    9693             :     int         i_cfgname;
    9694             :     int         i_cfgnamespace;
    9695             :     int         i_cfgowner;
    9696             :     int         i_cfgparser;
    9697             : 
    9698         304 :     query = createPQExpBuffer();
    9699             : 
    9700         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
    9701             :                          "cfgnamespace, cfgowner, cfgparser "
    9702             :                          "FROM pg_ts_config");
    9703             : 
    9704         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9705             : 
    9706         304 :     ntups = PQntuples(res);
    9707         304 :     *numTSConfigs = ntups;
    9708             : 
    9709         304 :     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
    9710             : 
    9711         304 :     i_tableoid = PQfnumber(res, "tableoid");
    9712         304 :     i_oid = PQfnumber(res, "oid");
    9713         304 :     i_cfgname = PQfnumber(res, "cfgname");
    9714         304 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
    9715         304 :     i_cfgowner = PQfnumber(res, "cfgowner");
    9716         304 :     i_cfgparser = PQfnumber(res, "cfgparser");
    9717             : 
    9718        9246 :     for (i = 0; i < ntups; i++)
    9719             :     {
    9720        8942 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
    9721        8942 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9722        8942 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9723        8942 :         AssignDumpId(&cfginfo[i].dobj);
    9724        8942 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
    9725       17884 :         cfginfo[i].dobj.namespace =
    9726        8942 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
    9727        8942 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
    9728        8942 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
    9729             : 
    9730             :         /* Decide whether we want to dump it */
    9731        8942 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
    9732             :     }
    9733             : 
    9734         304 :     PQclear(res);
    9735             : 
    9736         304 :     destroyPQExpBuffer(query);
    9737             : 
    9738         304 :     return cfginfo;
    9739             : }
    9740             : 
    9741             : /*
    9742             :  * getForeignDataWrappers:
    9743             :  *    read all foreign-data wrappers in the system catalogs and return
    9744             :  *    them in the FdwInfo* structure
    9745             :  *
    9746             :  *  numForeignDataWrappers is set to the number of fdws read in
    9747             :  */
    9748             : FdwInfo *
    9749         304 : getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
    9750             : {
    9751             :     PGresult   *res;
    9752             :     int         ntups;
    9753             :     int         i;
    9754             :     PQExpBuffer query;
    9755             :     FdwInfo    *fdwinfo;
    9756             :     int         i_tableoid;
    9757             :     int         i_oid;
    9758             :     int         i_fdwname;
    9759             :     int         i_fdwowner;
    9760             :     int         i_fdwhandler;
    9761             :     int         i_fdwvalidator;
    9762             :     int         i_fdwacl;
    9763             :     int         i_acldefault;
    9764             :     int         i_fdwoptions;
    9765             : 
    9766         304 :     query = createPQExpBuffer();
    9767             : 
    9768         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
    9769             :                          "fdwowner, "
    9770             :                          "fdwhandler::pg_catalog.regproc, "
    9771             :                          "fdwvalidator::pg_catalog.regproc, "
    9772             :                          "fdwacl, "
    9773             :                          "acldefault('F', fdwowner) AS acldefault, "
    9774             :                          "array_to_string(ARRAY("
    9775             :                          "SELECT quote_ident(option_name) || ' ' || "
    9776             :                          "quote_literal(option_value) "
    9777             :                          "FROM pg_options_to_table(fdwoptions) "
    9778             :                          "ORDER BY option_name"
    9779             :                          "), E',\n    ') AS fdwoptions "
    9780             :                          "FROM pg_foreign_data_wrapper");
    9781             : 
    9782         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9783             : 
    9784         304 :     ntups = PQntuples(res);
    9785         304 :     *numForeignDataWrappers = ntups;
    9786             : 
    9787         304 :     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
    9788             : 
    9789         304 :     i_tableoid = PQfnumber(res, "tableoid");
    9790         304 :     i_oid = PQfnumber(res, "oid");
    9791         304 :     i_fdwname = PQfnumber(res, "fdwname");
    9792         304 :     i_fdwowner = PQfnumber(res, "fdwowner");
    9793         304 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
    9794         304 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
    9795         304 :     i_fdwacl = PQfnumber(res, "fdwacl");
    9796         304 :     i_acldefault = PQfnumber(res, "acldefault");
    9797         304 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
    9798             : 
    9799         438 :     for (i = 0; i < ntups; i++)
    9800             :     {
    9801         134 :         fdwinfo[i].dobj.objType = DO_FDW;
    9802         134 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9803         134 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9804         134 :         AssignDumpId(&fdwinfo[i].dobj);
    9805         134 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
    9806         134 :         fdwinfo[i].dobj.namespace = NULL;
    9807         134 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
    9808         134 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9809         134 :         fdwinfo[i].dacl.privtype = 0;
    9810         134 :         fdwinfo[i].dacl.initprivs = NULL;
    9811         134 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
    9812         134 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
    9813         134 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
    9814         134 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
    9815             : 
    9816             :         /* Decide whether we want to dump it */
    9817         134 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
    9818             : 
    9819             :         /* Mark whether FDW has an ACL */
    9820         134 :         if (!PQgetisnull(res, i, i_fdwacl))
    9821          86 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9822             :     }
    9823             : 
    9824         304 :     PQclear(res);
    9825             : 
    9826         304 :     destroyPQExpBuffer(query);
    9827             : 
    9828         304 :     return fdwinfo;
    9829             : }
    9830             : 
    9831             : /*
    9832             :  * getForeignServers:
    9833             :  *    read all foreign servers in the system catalogs and return
    9834             :  *    them in the ForeignServerInfo * structure
    9835             :  *
    9836             :  *  numForeignServers is set to the number of servers read in
    9837             :  */
    9838             : ForeignServerInfo *
    9839         304 : getForeignServers(Archive *fout, int *numForeignServers)
    9840             : {
    9841             :     PGresult   *res;
    9842             :     int         ntups;
    9843             :     int         i;
    9844             :     PQExpBuffer query;
    9845             :     ForeignServerInfo *srvinfo;
    9846             :     int         i_tableoid;
    9847             :     int         i_oid;
    9848             :     int         i_srvname;
    9849             :     int         i_srvowner;
    9850             :     int         i_srvfdw;
    9851             :     int         i_srvtype;
    9852             :     int         i_srvversion;
    9853             :     int         i_srvacl;
    9854             :     int         i_acldefault;
    9855             :     int         i_srvoptions;
    9856             : 
    9857         304 :     query = createPQExpBuffer();
    9858             : 
    9859         304 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
    9860             :                          "srvowner, "
    9861             :                          "srvfdw, srvtype, srvversion, srvacl, "
    9862             :                          "acldefault('S', srvowner) AS acldefault, "
    9863             :                          "array_to_string(ARRAY("
    9864             :                          "SELECT quote_ident(option_name) || ' ' || "
    9865             :                          "quote_literal(option_value) "
    9866             :                          "FROM pg_options_to_table(srvoptions) "
    9867             :                          "ORDER BY option_name"
    9868             :                          "), E',\n    ') AS srvoptions "
    9869             :                          "FROM pg_foreign_server");
    9870             : 
    9871         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9872             : 
    9873         304 :     ntups = PQntuples(res);
    9874         304 :     *numForeignServers = ntups;
    9875             : 
    9876         304 :     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
    9877             : 
    9878         304 :     i_tableoid = PQfnumber(res, "tableoid");
    9879         304 :     i_oid = PQfnumber(res, "oid");
    9880         304 :     i_srvname = PQfnumber(res, "srvname");
    9881         304 :     i_srvowner = PQfnumber(res, "srvowner");
    9882         304 :     i_srvfdw = PQfnumber(res, "srvfdw");
    9883         304 :     i_srvtype = PQfnumber(res, "srvtype");
    9884         304 :     i_srvversion = PQfnumber(res, "srvversion");
    9885         304 :     i_srvacl = PQfnumber(res, "srvacl");
    9886         304 :     i_acldefault = PQfnumber(res, "acldefault");
    9887         304 :     i_srvoptions = PQfnumber(res, "srvoptions");
    9888             : 
    9889         446 :     for (i = 0; i < ntups; i++)
    9890             :     {
    9891         142 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
    9892         142 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9893         142 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9894         142 :         AssignDumpId(&srvinfo[i].dobj);
    9895         142 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
    9896         142 :         srvinfo[i].dobj.namespace = NULL;
    9897         142 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
    9898         142 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9899         142 :         srvinfo[i].dacl.privtype = 0;
    9900         142 :         srvinfo[i].dacl.initprivs = NULL;
    9901         142 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
    9902         142 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
    9903         142 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
    9904         142 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
    9905         142 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
    9906             : 
    9907             :         /* Decide whether we want to dump it */
    9908         142 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
    9909             : 
    9910             :         /* Servers have user mappings */
    9911         142 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
    9912             : 
    9913             :         /* Mark whether server has an ACL */
    9914         142 :         if (!PQgetisnull(res, i, i_srvacl))
    9915          86 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9916             :     }
    9917             : 
    9918         304 :     PQclear(res);
    9919             : 
    9920         304 :     destroyPQExpBuffer(query);
    9921             : 
    9922         304 :     return srvinfo;
    9923             : }
    9924             : 
    9925             : /*
    9926             :  * getDefaultACLs:
    9927             :  *    read all default ACL information in the system catalogs and return
    9928             :  *    them in the DefaultACLInfo structure
    9929             :  *
    9930             :  *  numDefaultACLs is set to the number of ACLs read in
    9931             :  */
    9932             : DefaultACLInfo *
    9933         304 : getDefaultACLs(Archive *fout, int *numDefaultACLs)
    9934             : {
    9935         304 :     DumpOptions *dopt = fout->dopt;
    9936             :     DefaultACLInfo *daclinfo;
    9937             :     PQExpBuffer query;
    9938             :     PGresult   *res;
    9939             :     int         i_oid;
    9940             :     int         i_tableoid;
    9941             :     int         i_defaclrole;
    9942             :     int         i_defaclnamespace;
    9943             :     int         i_defaclobjtype;
    9944             :     int         i_defaclacl;
    9945             :     int         i_acldefault;
    9946             :     int         i,
    9947             :                 ntups;
    9948             : 
    9949         304 :     query = createPQExpBuffer();
    9950             : 
    9951             :     /*
    9952             :      * Global entries (with defaclnamespace=0) replace the hard-wired default
    9953             :      * ACL for their object type.  We should dump them as deltas from the
    9954             :      * default ACL, since that will be used as a starting point for
    9955             :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
    9956             :      * non-global entries can only add privileges not revoke them.  We must
    9957             :      * dump those as-is (i.e., as deltas from an empty ACL).
    9958             :      *
    9959             :      * We can use defaclobjtype as the object type for acldefault(), except
    9960             :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
    9961             :      * 's'.
    9962             :      */
    9963         304 :     appendPQExpBufferStr(query,
    9964             :                          "SELECT oid, tableoid, "
    9965             :                          "defaclrole, "
    9966             :                          "defaclnamespace, "
    9967             :                          "defaclobjtype, "
    9968             :                          "defaclacl, "
    9969             :                          "CASE WHEN defaclnamespace = 0 THEN "
    9970             :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
    9971             :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
    9972             :                          "defaclrole) ELSE '{}' END AS acldefault "
    9973             :                          "FROM pg_default_acl");
    9974             : 
    9975         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9976             : 
    9977         304 :     ntups = PQntuples(res);
    9978         304 :     *numDefaultACLs = ntups;
    9979             : 
    9980         304 :     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
    9981             : 
    9982         304 :     i_oid = PQfnumber(res, "oid");
    9983         304 :     i_tableoid = PQfnumber(res, "tableoid");
    9984         304 :     i_defaclrole = PQfnumber(res, "defaclrole");
    9985         304 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
    9986         304 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
    9987         304 :     i_defaclacl = PQfnumber(res, "defaclacl");
    9988         304 :     i_acldefault = PQfnumber(res, "acldefault");
    9989             : 
    9990         648 :     for (i = 0; i < ntups; i++)
    9991             :     {
    9992         344 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
    9993             : 
    9994         344 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
    9995         344 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9996         344 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9997         344 :         AssignDumpId(&daclinfo[i].dobj);
    9998             :         /* cheesy ... is it worth coming up with a better object name? */
    9999         344 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10000             : 
   10001         344 :         if (nspid != InvalidOid)
   10002         172 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10003             :         else
   10004         172 :             daclinfo[i].dobj.namespace = NULL;
   10005             : 
   10006         344 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10007         344 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10008         344 :         daclinfo[i].dacl.privtype = 0;
   10009         344 :         daclinfo[i].dacl.initprivs = NULL;
   10010         344 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10011         344 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10012             : 
   10013             :         /* Default ACLs are ACLs, of course */
   10014         344 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10015             : 
   10016             :         /* Decide whether we want to dump it */
   10017         344 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10018             :     }
   10019             : 
   10020         304 :     PQclear(res);
   10021             : 
   10022         304 :     destroyPQExpBuffer(query);
   10023             : 
   10024         304 :     return daclinfo;
   10025             : }
   10026             : 
   10027             : /*
   10028             :  * getRoleName -- look up the name of a role, given its OID
   10029             :  *
   10030             :  * In current usage, we don't expect failures, so error out for a bad OID.
   10031             :  */
   10032             : static const char *
   10033      942884 : getRoleName(const char *roleoid_str)
   10034             : {
   10035      942884 :     Oid         roleoid = atooid(roleoid_str);
   10036             : 
   10037             :     /*
   10038             :      * Do binary search to find the appropriate item.
   10039             :      */
   10040      942884 :     if (nrolenames > 0)
   10041             :     {
   10042      942884 :         RoleNameItem *low = &rolenames[0];
   10043      942884 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10044             : 
   10045     3771646 :         while (low <= high)
   10046             :         {
   10047     3771646 :             RoleNameItem *middle = low + (high - low) / 2;
   10048             : 
   10049     3771646 :             if (roleoid < middle->roleoid)
   10050     2826458 :                 high = middle - 1;
   10051      945188 :             else if (roleoid > middle->roleoid)
   10052        2304 :                 low = middle + 1;
   10053             :             else
   10054      942884 :                 return middle->rolename; /* found a match */
   10055             :         }
   10056             :     }
   10057             : 
   10058           0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10059             :     return NULL;                /* keep compiler quiet */
   10060             : }
   10061             : 
   10062             : /*
   10063             :  * collectRoleNames --
   10064             :  *
   10065             :  * Construct a table of all known roles.
   10066             :  * The table is sorted by OID for speed in lookup.
   10067             :  */
   10068             : static void
   10069         306 : collectRoleNames(Archive *fout)
   10070             : {
   10071             :     PGresult   *res;
   10072             :     const char *query;
   10073             :     int         i;
   10074             : 
   10075         306 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10076             : 
   10077         306 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10078             : 
   10079         306 :     nrolenames = PQntuples(res);
   10080             : 
   10081         306 :     rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
   10082             : 
   10083        5602 :     for (i = 0; i < nrolenames; i++)
   10084             :     {
   10085        5296 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10086        5296 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10087             :     }
   10088             : 
   10089         306 :     PQclear(res);
   10090         306 : }
   10091             : 
   10092             : /*
   10093             :  * getAdditionalACLs
   10094             :  *
   10095             :  * We have now created all the DumpableObjects, and collected the ACL data
   10096             :  * that appears in the directly-associated catalog entries.  However, there's
   10097             :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10098             :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10099             :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10100             :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10101             :  * information into the relevant DumpableObjects.
   10102             :  */
   10103             : static void
   10104         300 : getAdditionalACLs(Archive *fout)
   10105             : {
   10106         300 :     PQExpBuffer query = createPQExpBuffer();
   10107             :     PGresult   *res;
   10108             :     int         ntups,
   10109             :                 i;
   10110             : 
   10111             :     /* Check for per-column ACLs */
   10112         300 :     appendPQExpBufferStr(query,
   10113             :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10114             :                          "WHERE attacl IS NOT NULL");
   10115             : 
   10116         300 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10117             : 
   10118         300 :     ntups = PQntuples(res);
   10119         920 :     for (i = 0; i < ntups; i++)
   10120             :     {
   10121         620 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10122             :         TableInfo  *tblinfo;
   10123             : 
   10124         620 :         tblinfo = findTableByOid(relid);
   10125             :         /* OK to ignore tables we haven't got a DumpableObject for */
   10126         620 :         if (tblinfo)
   10127             :         {
   10128         620 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10129         620 :             tblinfo->hascolumnACLs = true;
   10130             :         }
   10131             :     }
   10132         300 :     PQclear(res);
   10133             : 
   10134             :     /* Fetch initial-privileges data */
   10135         300 :     if (fout->remoteVersion >= 90600)
   10136             :     {
   10137         300 :         printfPQExpBuffer(query,
   10138             :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10139             :                           "FROM pg_init_privs");
   10140             : 
   10141         300 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10142             : 
   10143         300 :         ntups = PQntuples(res);
   10144       67816 :         for (i = 0; i < ntups; i++)
   10145             :         {
   10146       67516 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10147       67516 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10148       67516 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10149       67516 :             char        privtype = *(PQgetvalue(res, i, 3));
   10150       67516 :             char       *initprivs = PQgetvalue(res, i, 4);
   10151             :             CatalogId   objId;
   10152             :             DumpableObject *dobj;
   10153             : 
   10154       67516 :             objId.tableoid = classoid;
   10155       67516 :             objId.oid = objoid;
   10156       67516 :             dobj = findObjectByCatalogId(objId);
   10157             :             /* OK to ignore entries we haven't got a DumpableObject for */
   10158       67516 :             if (dobj)
   10159             :             {
   10160             :                 /* Cope with sub-object initprivs */
   10161       49000 :                 if (objsubid != 0)
   10162             :                 {
   10163        5148 :                     if (dobj->objType == DO_TABLE)
   10164             :                     {
   10165             :                         /* For a column initprivs, set the table's ACL flags */
   10166        5148 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10167        5148 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10168             :                     }
   10169             :                     else
   10170           0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10171             :                                        classoid, objoid, objsubid);
   10172        5440 :                     continue;
   10173             :                 }
   10174             : 
   10175             :                 /*
   10176             :                  * We ignore any pg_init_privs.initprivs entry for the public
   10177             :                  * schema, as explained in getNamespaces().
   10178             :                  */
   10179       43852 :                 if (dobj->objType == DO_NAMESPACE &&
   10180         592 :                     strcmp(dobj->name, "public") == 0)
   10181         292 :                     continue;
   10182             : 
   10183             :                 /* Else it had better be of a type we think has ACLs */
   10184       43560 :                 if (dobj->objType == DO_NAMESPACE ||
   10185       43260 :                     dobj->objType == DO_TYPE ||
   10186       43212 :                     dobj->objType == DO_FUNC ||
   10187       43032 :                     dobj->objType == DO_AGG ||
   10188       42984 :                     dobj->objType == DO_TABLE ||
   10189           0 :                     dobj->objType == DO_PROCLANG ||
   10190           0 :                     dobj->objType == DO_FDW ||
   10191           0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10192       43560 :                 {
   10193       43560 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10194             : 
   10195       43560 :                     daobj->dacl.privtype = privtype;
   10196       43560 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10197             :                 }
   10198             :                 else
   10199           0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10200             :                                    classoid, objoid, objsubid);
   10201             :             }
   10202             :         }
   10203         300 :         PQclear(res);
   10204             :     }
   10205             : 
   10206         300 :     destroyPQExpBuffer(query);
   10207         300 : }
   10208             : 
   10209             : /*
   10210             :  * dumpCommentExtended --
   10211             :  *
   10212             :  * This routine is used to dump any comments associated with the
   10213             :  * object handed to this routine. The routine takes the object type
   10214             :  * and object name (ready to print, except for schema decoration), plus
   10215             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10216             :  * plus catalog ID and subid which are the lookup key for pg_description,
   10217             :  * plus the dump ID for the object (for setting a dependency).
   10218             :  * If a matching pg_description entry is found, it is dumped.
   10219             :  *
   10220             :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10221             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10222             :  * but it doesn't seem worth complicating the API for all callers to make
   10223             :  * it cleaner.
   10224             :  *
   10225             :  * Note: although this routine takes a dumpId for dependency purposes,
   10226             :  * that purpose is just to mark the dependency in the emitted dump file
   10227             :  * for possible future use by pg_restore.  We do NOT use it for determining
   10228             :  * ordering of the comment in the dump file, because this routine is called
   10229             :  * after dependency sorting occurs.  This routine should be called just after
   10230             :  * calling ArchiveEntry() for the specified object.
   10231             :  */
   10232             : static void
   10233        5148 : dumpCommentExtended(Archive *fout, const char *type,
   10234             :                     const char *name, const char *namespace,
   10235             :                     const char *owner, CatalogId catalogId,
   10236             :                     int subid, DumpId dumpId,
   10237             :                     const char *initdb_comment)
   10238             : {
   10239        5148 :     DumpOptions *dopt = fout->dopt;
   10240             :     CommentItem *comments;
   10241             :     int         ncomments;
   10242             : 
   10243             :     /* do nothing, if --no-comments is supplied */
   10244        5148 :     if (dopt->no_comments)
   10245           0 :         return;
   10246             : 
   10247             :     /* Comments are schema not data ... except LO comments are data */
   10248        5148 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10249             :     {
   10250        5050 :         if (dopt->dataOnly)
   10251           0 :             return;
   10252             :     }
   10253             :     else
   10254             :     {
   10255             :         /* We do dump LO comments in binary-upgrade mode */
   10256          98 :         if (dopt->schemaOnly && !dopt->binary_upgrade)
   10257           0 :             return;
   10258             :     }
   10259             : 
   10260             :     /* Search for comments associated with catalogId, using table */
   10261        5148 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10262             :                              &comments);
   10263             : 
   10264             :     /* Is there one matching the subid? */
   10265        5148 :     while (ncomments > 0)
   10266             :     {
   10267        5064 :         if (comments->objsubid == subid)
   10268        5064 :             break;
   10269           0 :         comments++;
   10270           0 :         ncomments--;
   10271             :     }
   10272             : 
   10273        5148 :     if (initdb_comment != NULL)
   10274             :     {
   10275             :         static CommentItem empty_comment = {.descr = ""};
   10276             : 
   10277             :         /*
   10278             :          * initdb creates this object with a comment.  Skip dumping the
   10279             :          * initdb-provided comment, which would complicate matters for
   10280             :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10281             :          * comment, replicate that.
   10282             :          */
   10283         220 :         if (ncomments == 0)
   10284             :         {
   10285           8 :             comments = &empty_comment;
   10286           8 :             ncomments = 1;
   10287             :         }
   10288         212 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10289         212 :             ncomments = 0;
   10290             :     }
   10291             : 
   10292             :     /* If a comment exists, build COMMENT ON statement */
   10293        5148 :     if (ncomments > 0)
   10294             :     {
   10295        4860 :         PQExpBuffer query = createPQExpBuffer();
   10296        4860 :         PQExpBuffer tag = createPQExpBuffer();
   10297             : 
   10298        4860 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10299        4860 :         if (namespace && *namespace)
   10300        4570 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10301        4860 :         appendPQExpBuffer(query, "%s IS ", name);
   10302        4860 :         appendStringLiteralAH(query, comments->descr, fout);
   10303        4860 :         appendPQExpBufferStr(query, ";\n");
   10304             : 
   10305        4860 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10306             : 
   10307             :         /*
   10308             :          * We mark comments as SECTION_NONE because they really belong in the
   10309             :          * same section as their parent, whether that is pre-data or
   10310             :          * post-data.
   10311             :          */
   10312        4860 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10313        4860 :                      ARCHIVE_OPTS(.tag = tag->data,
   10314             :                                   .namespace = namespace,
   10315             :                                   .owner = owner,
   10316             :                                   .description = "COMMENT",
   10317             :                                   .section = SECTION_NONE,
   10318             :                                   .createStmt = query->data,
   10319             :                                   .deps = &dumpId,
   10320             :                                   .nDeps = 1));
   10321             : 
   10322        4860 :         destroyPQExpBuffer(query);
   10323        4860 :         destroyPQExpBuffer(tag);
   10324             :     }
   10325             : }
   10326             : 
   10327             : /*
   10328             :  * dumpComment --
   10329             :  *
   10330             :  * Typical simplification of the above function.
   10331             :  */
   10332             : static inline void
   10333        4898 : dumpComment(Archive *fout, const char *type,
   10334             :             const char *name, const char *namespace,
   10335             :             const char *owner, CatalogId catalogId,
   10336             :             int subid, DumpId dumpId)
   10337             : {
   10338        4898 :     dumpCommentExtended(fout, type, name, namespace, owner,
   10339             :                         catalogId, subid, dumpId, NULL);
   10340        4898 : }
   10341             : 
   10342             : /*
   10343             :  * dumpTableComment --
   10344             :  *
   10345             :  * As above, but dump comments for both the specified table (or view)
   10346             :  * and its columns.
   10347             :  */
   10348             : static void
   10349         152 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   10350             :                  const char *reltypename)
   10351             : {
   10352         152 :     DumpOptions *dopt = fout->dopt;
   10353             :     CommentItem *comments;
   10354             :     int         ncomments;
   10355             :     PQExpBuffer query;
   10356             :     PQExpBuffer tag;
   10357             : 
   10358             :     /* do nothing, if --no-comments is supplied */
   10359         152 :     if (dopt->no_comments)
   10360           0 :         return;
   10361             : 
   10362             :     /* Comments are SCHEMA not data */
   10363         152 :     if (dopt->dataOnly)
   10364           0 :         return;
   10365             : 
   10366             :     /* Search for comments associated with relation, using table */
   10367         152 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   10368             :                              tbinfo->dobj.catId.oid,
   10369             :                              &comments);
   10370             : 
   10371             :     /* If comments exist, build COMMENT ON statements */
   10372         152 :     if (ncomments <= 0)
   10373           0 :         return;
   10374             : 
   10375         152 :     query = createPQExpBuffer();
   10376         152 :     tag = createPQExpBuffer();
   10377             : 
   10378         436 :     while (ncomments > 0)
   10379             :     {
   10380         284 :         const char *descr = comments->descr;
   10381         284 :         int         objsubid = comments->objsubid;
   10382             : 
   10383         284 :         if (objsubid == 0)
   10384             :         {
   10385          66 :             resetPQExpBuffer(tag);
   10386          66 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   10387          66 :                               fmtId(tbinfo->dobj.name));
   10388             : 
   10389          66 :             resetPQExpBuffer(query);
   10390          66 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   10391          66 :                               fmtQualifiedDumpable(tbinfo));
   10392          66 :             appendStringLiteralAH(query, descr, fout);
   10393          66 :             appendPQExpBufferStr(query, ";\n");
   10394             : 
   10395          66 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10396          66 :                          ARCHIVE_OPTS(.tag = tag->data,
   10397             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10398             :                                       .owner = tbinfo->rolname,
   10399             :                                       .description = "COMMENT",
   10400             :                                       .section = SECTION_NONE,
   10401             :                                       .createStmt = query->data,
   10402             :                                       .deps = &(tbinfo->dobj.dumpId),
   10403             :                                       .nDeps = 1));
   10404             :         }
   10405         218 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   10406             :         {
   10407         218 :             resetPQExpBuffer(tag);
   10408         218 :             appendPQExpBuffer(tag, "COLUMN %s.",
   10409         218 :                               fmtId(tbinfo->dobj.name));
   10410         218 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   10411             : 
   10412         218 :             resetPQExpBuffer(query);
   10413         218 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   10414         218 :                               fmtQualifiedDumpable(tbinfo));
   10415         218 :             appendPQExpBuffer(query, "%s IS ",
   10416         218 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   10417         218 :             appendStringLiteralAH(query, descr, fout);
   10418         218 :             appendPQExpBufferStr(query, ";\n");
   10419             : 
   10420         218 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10421         218 :                          ARCHIVE_OPTS(.tag = tag->data,
   10422             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10423             :                                       .owner = tbinfo->rolname,
   10424             :                                       .description = "COMMENT",
   10425             :                                       .section = SECTION_NONE,
   10426             :                                       .createStmt = query->data,
   10427             :                                       .deps = &(tbinfo->dobj.dumpId),
   10428             :                                       .nDeps = 1));
   10429             :         }
   10430             : 
   10431         284 :         comments++;
   10432         284 :         ncomments--;
   10433             :     }
   10434             : 
   10435         152 :     destroyPQExpBuffer(query);
   10436         152 :     destroyPQExpBuffer(tag);
   10437             : }
   10438             : 
   10439             : /*
   10440             :  * findComments --
   10441             :  *
   10442             :  * Find the comment(s), if any, associated with the given object.  All the
   10443             :  * objsubid values associated with the given classoid/objoid are found with
   10444             :  * one search.
   10445             :  */
   10446             : static int
   10447        5366 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   10448             : {
   10449        5366 :     CommentItem *middle = NULL;
   10450             :     CommentItem *low;
   10451             :     CommentItem *high;
   10452             :     int         nmatch;
   10453             : 
   10454             :     /*
   10455             :      * Do binary search to find some item matching the object.
   10456             :      */
   10457        5366 :     low = &comments[0];
   10458        5366 :     high = &comments[ncomments - 1];
   10459       53562 :     while (low <= high)
   10460             :     {
   10461       53478 :         middle = low + (high - low) / 2;
   10462             : 
   10463       53478 :         if (classoid < middle->classoid)
   10464        9080 :             high = middle - 1;
   10465       44398 :         else if (classoid > middle->classoid)
   10466        7812 :             low = middle + 1;
   10467       36586 :         else if (objoid < middle->objoid)
   10468       14324 :             high = middle - 1;
   10469       22262 :         else if (objoid > middle->objoid)
   10470       16980 :             low = middle + 1;
   10471             :         else
   10472        5282 :             break;              /* found a match */
   10473             :     }
   10474             : 
   10475        5366 :     if (low > high)              /* no matches */
   10476             :     {
   10477          84 :         *items = NULL;
   10478          84 :         return 0;
   10479             :     }
   10480             : 
   10481             :     /*
   10482             :      * Now determine how many items match the object.  The search loop
   10483             :      * invariant still holds: only items between low and high inclusive could
   10484             :      * match.
   10485             :      */
   10486        5282 :     nmatch = 1;
   10487        5282 :     while (middle > low)
   10488             :     {
   10489        2420 :         if (classoid != middle[-1].classoid ||
   10490        2248 :             objoid != middle[-1].objoid)
   10491             :             break;
   10492           0 :         middle--;
   10493           0 :         nmatch++;
   10494             :     }
   10495             : 
   10496        5282 :     *items = middle;
   10497             : 
   10498        5282 :     middle += nmatch;
   10499        5414 :     while (middle <= high)
   10500             :     {
   10501        2762 :         if (classoid != middle->classoid ||
   10502        2302 :             objoid != middle->objoid)
   10503             :             break;
   10504         132 :         middle++;
   10505         132 :         nmatch++;
   10506             :     }
   10507             : 
   10508        5282 :     return nmatch;
   10509             : }
   10510             : 
   10511             : /*
   10512             :  * collectComments --
   10513             :  *
   10514             :  * Construct a table of all comments available for database objects;
   10515             :  * also set the has-comment component flag for each relevant object.
   10516             :  *
   10517             :  * We used to do per-object queries for the comments, but it's much faster
   10518             :  * to pull them all over at once, and on most databases the memory cost
   10519             :  * isn't high.
   10520             :  *
   10521             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   10522             :  */
   10523             : static void
   10524         304 : collectComments(Archive *fout)
   10525             : {
   10526             :     PGresult   *res;
   10527             :     PQExpBuffer query;
   10528             :     int         i_description;
   10529             :     int         i_classoid;
   10530             :     int         i_objoid;
   10531             :     int         i_objsubid;
   10532             :     int         ntups;
   10533             :     int         i;
   10534             :     DumpableObject *dobj;
   10535             : 
   10536         304 :     query = createPQExpBuffer();
   10537             : 
   10538         304 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   10539             :                          "FROM pg_catalog.pg_description "
   10540             :                          "ORDER BY classoid, objoid, objsubid");
   10541             : 
   10542         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10543             : 
   10544             :     /* Construct lookup table containing OIDs in numeric form */
   10545             : 
   10546         304 :     i_description = PQfnumber(res, "description");
   10547         304 :     i_classoid = PQfnumber(res, "classoid");
   10548         304 :     i_objoid = PQfnumber(res, "objoid");
   10549         304 :     i_objsubid = PQfnumber(res, "objsubid");
   10550             : 
   10551         304 :     ntups = PQntuples(res);
   10552             : 
   10553         304 :     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
   10554         304 :     ncomments = 0;
   10555         304 :     dobj = NULL;
   10556             : 
   10557     1584810 :     for (i = 0; i < ntups; i++)
   10558             :     {
   10559             :         CatalogId   objId;
   10560             :         int         subid;
   10561             : 
   10562     1584506 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   10563     1584506 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   10564     1584506 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   10565             : 
   10566             :         /* We needn't remember comments that don't match any dumpable object */
   10567     1584506 :         if (dobj == NULL ||
   10568      575924 :             dobj->catId.tableoid != objId.tableoid ||
   10569      572138 :             dobj->catId.oid != objId.oid)
   10570     1584334 :             dobj = findObjectByCatalogId(objId);
   10571     1584506 :         if (dobj == NULL)
   10572     1008286 :             continue;
   10573             : 
   10574             :         /*
   10575             :          * Comments on columns of composite types are linked to the type's
   10576             :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   10577             :          * in the type's own DumpableObject.
   10578             :          */
   10579      576220 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   10580         364 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   10581          86 :         {
   10582             :             TypeInfo   *cTypeInfo;
   10583             : 
   10584          86 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   10585          86 :             if (cTypeInfo)
   10586          86 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   10587             :         }
   10588             :         else
   10589      576134 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   10590             : 
   10591      576220 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   10592      576220 :         comments[ncomments].classoid = objId.tableoid;
   10593      576220 :         comments[ncomments].objoid = objId.oid;
   10594      576220 :         comments[ncomments].objsubid = subid;
   10595      576220 :         ncomments++;
   10596             :     }
   10597             : 
   10598         304 :     PQclear(res);
   10599         304 :     destroyPQExpBuffer(query);
   10600         304 : }
   10601             : 
   10602             : /*
   10603             :  * dumpDumpableObject
   10604             :  *
   10605             :  * This routine and its subsidiaries are responsible for creating
   10606             :  * ArchiveEntries (TOC objects) for each object to be dumped.
   10607             :  */
   10608             : static void
   10609     1098304 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   10610             : {
   10611             :     /*
   10612             :      * Clear any dump-request bits for components that don't exist for this
   10613             :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   10614             :      * request for every kind of object.)
   10615             :      */
   10616     1098304 :     dobj->dump &= dobj->components;
   10617             : 
   10618             :     /* Now, short-circuit if there's nothing to be done here. */
   10619     1098304 :     if (dobj->dump == 0)
   10620      985608 :         return;
   10621             : 
   10622      112696 :     switch (dobj->objType)
   10623             :     {
   10624         770 :         case DO_NAMESPACE:
   10625         770 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   10626         770 :             break;
   10627          38 :         case DO_EXTENSION:
   10628          38 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   10629          38 :             break;
   10630        1258 :         case DO_TYPE:
   10631        1258 :             dumpType(fout, (const TypeInfo *) dobj);
   10632        1258 :             break;
   10633         142 :         case DO_SHELL_TYPE:
   10634         142 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   10635         142 :             break;
   10636        3518 :         case DO_FUNC:
   10637        3518 :             dumpFunc(fout, (const FuncInfo *) dobj);
   10638        3518 :             break;
   10639         580 :         case DO_AGG:
   10640         580 :             dumpAgg(fout, (const AggInfo *) dobj);
   10641         580 :             break;
   10642        1808 :         case DO_OPERATOR:
   10643        1808 :             dumpOpr(fout, (const OprInfo *) dobj);
   10644        1808 :             break;
   10645         152 :         case DO_ACCESS_METHOD:
   10646         152 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   10647         152 :             break;
   10648         600 :         case DO_OPCLASS:
   10649         600 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   10650         600 :             break;
   10651         506 :         case DO_OPFAMILY:
   10652         506 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   10653         506 :             break;
   10654        1744 :         case DO_COLLATION:
   10655        1744 :             dumpCollation(fout, (const CollInfo *) dobj);
   10656        1744 :             break;
   10657         328 :         case DO_CONVERSION:
   10658         328 :             dumpConversion(fout, (const ConvInfo *) dobj);
   10659         328 :             break;
   10660       49336 :         case DO_TABLE:
   10661       49336 :             dumpTable(fout, (const TableInfo *) dobj);
   10662       49336 :             break;
   10663        2476 :         case DO_TABLE_ATTACH:
   10664        2476 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   10665        2476 :             break;
   10666        1520 :         case DO_ATTRDEF:
   10667        1520 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   10668        1520 :             break;
   10669        4244 :         case DO_INDEX:
   10670        4244 :             dumpIndex(fout, (const IndxInfo *) dobj);
   10671        4244 :             break;
   10672        1086 :         case DO_INDEX_ATTACH:
   10673        1086 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   10674        1086 :             break;
   10675         254 :         case DO_STATSEXT:
   10676         254 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   10677         254 :             break;
   10678         676 :         case DO_REFRESH_MATVIEW:
   10679         676 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   10680         676 :             break;
   10681        1820 :         case DO_RULE:
   10682        1820 :             dumpRule(fout, (const RuleInfo *) dobj);
   10683        1820 :             break;
   10684         986 :         case DO_TRIGGER:
   10685         986 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   10686         986 :             break;
   10687          80 :         case DO_EVENT_TRIGGER:
   10688          80 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   10689          80 :             break;
   10690        3542 :         case DO_CONSTRAINT:
   10691        3542 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   10692        3542 :             break;
   10693         344 :         case DO_FK_CONSTRAINT:
   10694         344 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   10695         344 :             break;
   10696         156 :         case DO_PROCLANG:
   10697         156 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   10698         156 :             break;
   10699         130 :         case DO_CAST:
   10700         130 :             dumpCast(fout, (const CastInfo *) dobj);
   10701         130 :             break;
   10702          80 :         case DO_TRANSFORM:
   10703          80 :             dumpTransform(fout, (const TransformInfo *) dobj);
   10704          80 :             break;
   10705         722 :         case DO_SEQUENCE_SET:
   10706         722 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   10707         722 :             break;
   10708        7024 :         case DO_TABLE_DATA:
   10709        7024 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   10710        7024 :             break;
   10711       23092 :         case DO_DUMMY_TYPE:
   10712             :             /* table rowtypes and array types are never dumped separately */
   10713       23092 :             break;
   10714          74 :         case DO_TSPARSER:
   10715          74 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   10716          74 :             break;
   10717         220 :         case DO_TSDICT:
   10718         220 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   10719         220 :             break;
   10720          82 :         case DO_TSTEMPLATE:
   10721          82 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   10722          82 :             break;
   10723         170 :         case DO_TSCONFIG:
   10724         170 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   10725         170 :             break;
   10726         100 :         case DO_FDW:
   10727         100 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   10728         100 :             break;
   10729         108 :         case DO_FOREIGN_SERVER:
   10730         108 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   10731         108 :             break;
   10732         284 :         case DO_DEFAULT_ACL:
   10733         284 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   10734         284 :             break;
   10735         146 :         case DO_LARGE_OBJECT:
   10736         146 :             dumpLO(fout, (const LoInfo *) dobj);
   10737         146 :             break;
   10738         146 :         case DO_LARGE_OBJECT_DATA:
   10739         146 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   10740             :             {
   10741             :                 LoInfo     *loinfo;
   10742             :                 TocEntry   *te;
   10743             : 
   10744         146 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   10745         146 :                 if (loinfo == NULL)
   10746           0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   10747             :                              dobj->name);
   10748             : 
   10749         146 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   10750         146 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   10751             :                                                .owner = loinfo->rolname,
   10752             :                                                .description = "BLOBS",
   10753             :                                                .section = SECTION_DATA,
   10754             :                                                .deps = dobj->dependencies,
   10755             :                                                .nDeps = dobj->nDeps,
   10756             :                                                .dumpFn = dumpLOs,
   10757             :                                                .dumpArg = loinfo));
   10758             : 
   10759             :                 /*
   10760             :                  * Set the TocEntry's dataLength in case we are doing a
   10761             :                  * parallel dump and want to order dump jobs by table size.
   10762             :                  * (We need some size estimate for every TocEntry with a
   10763             :                  * DataDumper function.)  We don't currently have any cheap
   10764             :                  * way to estimate the size of LOs, but fortunately it doesn't
   10765             :                  * matter too much as long as we get large batches of LOs
   10766             :                  * processed reasonably early.  Assume 8K per blob.
   10767             :                  */
   10768         146 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   10769             :             }
   10770         146 :             break;
   10771         638 :         case DO_POLICY:
   10772         638 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   10773         638 :             break;
   10774         282 :         case DO_PUBLICATION:
   10775         282 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   10776         282 :             break;
   10777         470 :         case DO_PUBLICATION_REL:
   10778         470 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   10779         470 :             break;
   10780         138 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   10781         138 :             dumpPublicationNamespace(fout,
   10782             :                                      (const PublicationSchemaInfo *) dobj);
   10783         138 :             break;
   10784         214 :         case DO_SUBSCRIPTION:
   10785         214 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   10786         214 :             break;
   10787           4 :         case DO_SUBSCRIPTION_REL:
   10788           4 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   10789           4 :             break;
   10790         608 :         case DO_PRE_DATA_BOUNDARY:
   10791             :         case DO_POST_DATA_BOUNDARY:
   10792             :             /* never dumped, nothing to do */
   10793         608 :             break;
   10794             :     }
   10795             : }
   10796             : 
   10797             : /*
   10798             :  * dumpNamespace
   10799             :  *    writes out to fout the queries to recreate a user-defined namespace
   10800             :  */
   10801             : static void
   10802         770 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   10803             : {
   10804         770 :     DumpOptions *dopt = fout->dopt;
   10805             :     PQExpBuffer q;
   10806             :     PQExpBuffer delq;
   10807             :     char       *qnspname;
   10808             : 
   10809             :     /* Do nothing in data-only dump */
   10810         770 :     if (dopt->dataOnly)
   10811          32 :         return;
   10812             : 
   10813         738 :     q = createPQExpBuffer();
   10814         738 :     delq = createPQExpBuffer();
   10815             : 
   10816         738 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   10817             : 
   10818         738 :     if (nspinfo->create)
   10819             :     {
   10820         494 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   10821         494 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   10822             :     }
   10823             :     else
   10824             :     {
   10825             :         /* see selectDumpableNamespace() */
   10826         244 :         appendPQExpBufferStr(delq,
   10827             :                              "-- *not* dropping schema, since initdb creates it\n");
   10828         244 :         appendPQExpBufferStr(q,
   10829             :                              "-- *not* creating schema, since initdb creates it\n");
   10830             :     }
   10831             : 
   10832         738 :     if (dopt->binary_upgrade)
   10833          80 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   10834             :                                         "SCHEMA", qnspname, NULL);
   10835             : 
   10836         738 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   10837         312 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   10838         312 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   10839             :                                   .owner = nspinfo->rolname,
   10840             :                                   .description = "SCHEMA",
   10841             :                                   .section = SECTION_PRE_DATA,
   10842             :                                   .createStmt = q->data,
   10843             :                                   .dropStmt = delq->data));
   10844             : 
   10845             :     /* Dump Schema Comments and Security Labels */
   10846         738 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   10847             :     {
   10848         250 :         const char *initdb_comment = NULL;
   10849             : 
   10850         250 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   10851         220 :             initdb_comment = "standard public schema";
   10852         250 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   10853             :                             NULL, nspinfo->rolname,
   10854             :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   10855             :                             initdb_comment);
   10856             :     }
   10857             : 
   10858         738 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   10859           0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   10860             :                      NULL, nspinfo->rolname,
   10861             :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   10862             : 
   10863         738 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   10864         572 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   10865             :                 qnspname, NULL, NULL,
   10866             :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   10867             : 
   10868         738 :     free(qnspname);
   10869             : 
   10870         738 :     destroyPQExpBuffer(q);
   10871         738 :     destroyPQExpBuffer(delq);
   10872             : }
   10873             : 
   10874             : /*
   10875             :  * dumpExtension
   10876             :  *    writes out to fout the queries to recreate an extension
   10877             :  */
   10878             : static void
   10879          38 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   10880             : {
   10881          38 :     DumpOptions *dopt = fout->dopt;
   10882             :     PQExpBuffer q;
   10883             :     PQExpBuffer delq;
   10884             :     char       *qextname;
   10885             : 
   10886             :     /* Do nothing in data-only dump */
   10887          38 :     if (dopt->dataOnly)
   10888           2 :         return;
   10889             : 
   10890          36 :     q = createPQExpBuffer();
   10891          36 :     delq = createPQExpBuffer();
   10892             : 
   10893          36 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   10894             : 
   10895          36 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   10896             : 
   10897          36 :     if (!dopt->binary_upgrade)
   10898             :     {
   10899             :         /*
   10900             :          * In a regular dump, we simply create the extension, intentionally
   10901             :          * not specifying a version, so that the destination installation's
   10902             :          * default version is used.
   10903             :          *
   10904             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   10905             :          * types; but there are various scenarios in which it's convenient to
   10906             :          * manually create the desired extension before restoring, so we
   10907             :          * prefer to allow it to exist already.
   10908             :          */
   10909          34 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   10910          34 :                           qextname, fmtId(extinfo->namespace));
   10911             :     }
   10912             :     else
   10913             :     {
   10914             :         /*
   10915             :          * In binary-upgrade mode, it's critical to reproduce the state of the
   10916             :          * database exactly, so our procedure is to create an empty extension,
   10917             :          * restore all the contained objects normally, and add them to the
   10918             :          * extension one by one.  This function performs just the first of
   10919             :          * those steps.  binary_upgrade_extension_member() takes care of
   10920             :          * adding member objects as they're created.
   10921             :          */
   10922             :         int         i;
   10923             :         int         n;
   10924             : 
   10925           2 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   10926             : 
   10927             :         /*
   10928             :          * We unconditionally create the extension, so we must drop it if it
   10929             :          * exists.  This could happen if the user deleted 'plpgsql' and then
   10930             :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   10931             :          */
   10932           2 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   10933             : 
   10934           2 :         appendPQExpBufferStr(q,
   10935             :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   10936           2 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   10937           2 :         appendPQExpBufferStr(q, ", ");
   10938           2 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   10939           2 :         appendPQExpBufferStr(q, ", ");
   10940           2 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   10941           2 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   10942           2 :         appendPQExpBufferStr(q, ", ");
   10943             : 
   10944             :         /*
   10945             :          * Note that we're pushing extconfig (an OID array) back into
   10946             :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   10947             :          * preserved in binary upgrade.
   10948             :          */
   10949           2 :         if (strlen(extinfo->extconfig) > 2)
   10950           2 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   10951             :         else
   10952           0 :             appendPQExpBufferStr(q, "NULL");
   10953           2 :         appendPQExpBufferStr(q, ", ");
   10954           2 :         if (strlen(extinfo->extcondition) > 2)
   10955           2 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   10956             :         else
   10957           0 :             appendPQExpBufferStr(q, "NULL");
   10958           2 :         appendPQExpBufferStr(q, ", ");
   10959           2 :         appendPQExpBufferStr(q, "ARRAY[");
   10960           2 :         n = 0;
   10961           4 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   10962             :         {
   10963             :             DumpableObject *extobj;
   10964             : 
   10965           2 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   10966           2 :             if (extobj && extobj->objType == DO_EXTENSION)
   10967             :             {
   10968           0 :                 if (n++ > 0)
   10969           0 :                     appendPQExpBufferChar(q, ',');
   10970           0 :                 appendStringLiteralAH(q, extobj->name, fout);
   10971             :             }
   10972             :         }
   10973           2 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   10974           2 :         appendPQExpBufferStr(q, ");\n");
   10975             :     }
   10976             : 
   10977          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   10978          36 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   10979          36 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   10980             :                                   .description = "EXTENSION",
   10981             :                                   .section = SECTION_PRE_DATA,
   10982             :                                   .createStmt = q->data,
   10983             :                                   .dropStmt = delq->data));
   10984             : 
   10985             :     /* Dump Extension Comments and Security Labels */
   10986          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   10987          36 :         dumpComment(fout, "EXTENSION", qextname,
   10988             :                     NULL, "",
   10989             :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   10990             : 
   10991          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   10992           0 :         dumpSecLabel(fout, "EXTENSION", qextname,
   10993             :                      NULL, "",
   10994             :                      extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   10995             : 
   10996          36 :     free(qextname);
   10997             : 
   10998          36 :     destroyPQExpBuffer(q);
   10999          36 :     destroyPQExpBuffer(delq);
   11000             : }
   11001             : 
   11002             : /*
   11003             :  * dumpType
   11004             :  *    writes out to fout the queries to recreate a user-defined type
   11005             :  */
   11006             : static void
   11007        1258 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   11008             : {
   11009        1258 :     DumpOptions *dopt = fout->dopt;
   11010             : 
   11011             :     /* Do nothing in data-only dump */
   11012        1258 :     if (dopt->dataOnly)
   11013          44 :         return;
   11014             : 
   11015             :     /* Dump out in proper style */
   11016        1214 :     if (tyinfo->typtype == TYPTYPE_BASE)
   11017         276 :         dumpBaseType(fout, tyinfo);
   11018         938 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   11019         256 :         dumpDomain(fout, tyinfo);
   11020         682 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   11021         262 :         dumpCompositeType(fout, tyinfo);
   11022         420 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   11023         110 :         dumpEnumType(fout, tyinfo);
   11024         310 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   11025         184 :         dumpRangeType(fout, tyinfo);
   11026         126 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   11027          76 :         dumpUndefinedType(fout, tyinfo);
   11028             :     else
   11029          50 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   11030             :                        tyinfo->dobj.name);
   11031             : }
   11032             : 
   11033             : /*
   11034             :  * dumpEnumType
   11035             :  *    writes out to fout the queries to recreate a user-defined enum type
   11036             :  */
   11037             : static void
   11038         110 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   11039             : {
   11040         110 :     DumpOptions *dopt = fout->dopt;
   11041         110 :     PQExpBuffer q = createPQExpBuffer();
   11042         110 :     PQExpBuffer delq = createPQExpBuffer();
   11043         110 :     PQExpBuffer query = createPQExpBuffer();
   11044             :     PGresult   *res;
   11045             :     int         num,
   11046             :                 i;
   11047             :     Oid         enum_oid;
   11048             :     char       *qtypname;
   11049             :     char       *qualtypname;
   11050             :     char       *label;
   11051             :     int         i_enumlabel;
   11052             :     int         i_oid;
   11053             : 
   11054         110 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   11055             :     {
   11056             :         /* Set up query for enum-specific details */
   11057          80 :         appendPQExpBufferStr(query,
   11058             :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   11059             :                              "SELECT oid, enumlabel "
   11060             :                              "FROM pg_catalog.pg_enum "
   11061             :                              "WHERE enumtypid = $1 "
   11062             :                              "ORDER BY enumsortorder");
   11063             : 
   11064          80 :         ExecuteSqlStatement(fout, query->data);
   11065             : 
   11066          80 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   11067             :     }
   11068             : 
   11069         110 :     printfPQExpBuffer(query,
   11070             :                       "EXECUTE dumpEnumType('%u')",
   11071             :                       tyinfo->dobj.catId.oid);
   11072             : 
   11073         110 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11074             : 
   11075         110 :     num = PQntuples(res);
   11076             : 
   11077         110 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11078         110 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11079             : 
   11080             :     /*
   11081             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11082             :      * functions are generic and do not get dropped.
   11083             :      */
   11084         110 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11085             : 
   11086         110 :     if (dopt->binary_upgrade)
   11087          10 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11088             :                                                  tyinfo->dobj.catId.oid,
   11089             :                                                  false, false);
   11090             : 
   11091         110 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   11092             :                       qualtypname);
   11093             : 
   11094         110 :     if (!dopt->binary_upgrade)
   11095             :     {
   11096         100 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11097             : 
   11098             :         /* Labels with server-assigned oids */
   11099         732 :         for (i = 0; i < num; i++)
   11100             :         {
   11101         632 :             label = PQgetvalue(res, i, i_enumlabel);
   11102         632 :             if (i > 0)
   11103         532 :                 appendPQExpBufferChar(q, ',');
   11104         632 :             appendPQExpBufferStr(q, "\n    ");
   11105         632 :             appendStringLiteralAH(q, label, fout);
   11106             :         }
   11107             :     }
   11108             : 
   11109         110 :     appendPQExpBufferStr(q, "\n);\n");
   11110             : 
   11111         110 :     if (dopt->binary_upgrade)
   11112             :     {
   11113          10 :         i_oid = PQfnumber(res, "oid");
   11114          10 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11115             : 
   11116             :         /* Labels with dump-assigned (preserved) oids */
   11117         116 :         for (i = 0; i < num; i++)
   11118             :         {
   11119         106 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   11120         106 :             label = PQgetvalue(res, i, i_enumlabel);
   11121             : 
   11122         106 :             if (i == 0)
   11123          10 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   11124         106 :             appendPQExpBuffer(q,
   11125             :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   11126             :                               enum_oid);
   11127         106 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   11128         106 :             appendStringLiteralAH(q, label, fout);
   11129         106 :             appendPQExpBufferStr(q, ";\n\n");
   11130             :         }
   11131             :     }
   11132             : 
   11133         110 :     if (dopt->binary_upgrade)
   11134          10 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11135             :                                         "TYPE", qtypname,
   11136          10 :                                         tyinfo->dobj.namespace->dobj.name);
   11137             : 
   11138         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11139         110 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11140         110 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11141             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11142             :                                   .owner = tyinfo->rolname,
   11143             :                                   .description = "TYPE",
   11144             :                                   .section = SECTION_PRE_DATA,
   11145             :                                   .createStmt = q->data,
   11146             :                                   .dropStmt = delq->data));
   11147             : 
   11148             :     /* Dump Type Comments and Security Labels */
   11149         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11150          66 :         dumpComment(fout, "TYPE", qtypname,
   11151          66 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11152             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11153             : 
   11154         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11155           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11156           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11157             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11158             : 
   11159         110 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11160          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11161             :                 qtypname, NULL,
   11162          66 :                 tyinfo->dobj.namespace->dobj.name,
   11163             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11164             : 
   11165         110 :     PQclear(res);
   11166         110 :     destroyPQExpBuffer(q);
   11167         110 :     destroyPQExpBuffer(delq);
   11168         110 :     destroyPQExpBuffer(query);
   11169         110 :     free(qtypname);
   11170         110 :     free(qualtypname);
   11171         110 : }
   11172             : 
   11173             : /*
   11174             :  * dumpRangeType
   11175             :  *    writes out to fout the queries to recreate a user-defined range type
   11176             :  */
   11177             : static void
   11178         184 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   11179             : {
   11180         184 :     DumpOptions *dopt = fout->dopt;
   11181         184 :     PQExpBuffer q = createPQExpBuffer();
   11182         184 :     PQExpBuffer delq = createPQExpBuffer();
   11183         184 :     PQExpBuffer query = createPQExpBuffer();
   11184             :     PGresult   *res;
   11185             :     Oid         collationOid;
   11186             :     char       *qtypname;
   11187             :     char       *qualtypname;
   11188             :     char       *procname;
   11189             : 
   11190         184 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   11191             :     {
   11192             :         /* Set up query for range-specific details */
   11193          78 :         appendPQExpBufferStr(query,
   11194             :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   11195             : 
   11196          78 :         appendPQExpBufferStr(query,
   11197             :                              "SELECT ");
   11198             : 
   11199          78 :         if (fout->remoteVersion >= 140000)
   11200          78 :             appendPQExpBufferStr(query,
   11201             :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   11202             :         else
   11203           0 :             appendPQExpBufferStr(query,
   11204             :                                  "NULL AS rngmultitype, ");
   11205             : 
   11206          78 :         appendPQExpBufferStr(query,
   11207             :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   11208             :                              "opc.opcname AS opcname, "
   11209             :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   11210             :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   11211             :                              "opc.opcdefault, "
   11212             :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   11213             :                              "     ELSE rngcollation END AS collation, "
   11214             :                              "rngcanonical, rngsubdiff "
   11215             :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   11216             :                              "     pg_catalog.pg_opclass opc "
   11217             :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   11218             :                              "rngtypid = $1");
   11219             : 
   11220          78 :         ExecuteSqlStatement(fout, query->data);
   11221             : 
   11222          78 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   11223             :     }
   11224             : 
   11225         184 :     printfPQExpBuffer(query,
   11226             :                       "EXECUTE dumpRangeType('%u')",
   11227             :                       tyinfo->dobj.catId.oid);
   11228             : 
   11229         184 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11230             : 
   11231         184 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11232         184 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11233             : 
   11234             :     /*
   11235             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11236             :      * functions are generic and do not get dropped.
   11237             :      */
   11238         184 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11239             : 
   11240         184 :     if (dopt->binary_upgrade)
   11241          12 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11242             :                                                  tyinfo->dobj.catId.oid,
   11243             :                                                  false, true);
   11244             : 
   11245         184 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   11246             :                       qualtypname);
   11247             : 
   11248         184 :     appendPQExpBuffer(q, "\n    subtype = %s",
   11249             :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   11250             : 
   11251         184 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   11252         184 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   11253             :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   11254             : 
   11255             :     /* print subtype_opclass only if not default for subtype */
   11256         184 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   11257             :     {
   11258          66 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   11259          66 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   11260             : 
   11261          66 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   11262             :                           fmtId(nspname));
   11263          66 :         appendPQExpBufferStr(q, fmtId(opcname));
   11264             :     }
   11265             : 
   11266         184 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   11267         184 :     if (OidIsValid(collationOid))
   11268             :     {
   11269          76 :         CollInfo   *coll = findCollationByOid(collationOid);
   11270             : 
   11271          76 :         if (coll)
   11272          76 :             appendPQExpBuffer(q, ",\n    collation = %s",
   11273          76 :                               fmtQualifiedDumpable(coll));
   11274             :     }
   11275             : 
   11276         184 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   11277         184 :     if (strcmp(procname, "-") != 0)
   11278           6 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   11279             : 
   11280         184 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   11281         184 :     if (strcmp(procname, "-") != 0)
   11282          22 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   11283             : 
   11284         184 :     appendPQExpBufferStr(q, "\n);\n");
   11285             : 
   11286         184 :     if (dopt->binary_upgrade)
   11287          12 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11288             :                                         "TYPE", qtypname,
   11289          12 :                                         tyinfo->dobj.namespace->dobj.name);
   11290             : 
   11291         184 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11292         184 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11293         184 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11294             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11295             :                                   .owner = tyinfo->rolname,
   11296             :                                   .description = "TYPE",
   11297             :                                   .section = SECTION_PRE_DATA,
   11298             :                                   .createStmt = q->data,
   11299             :                                   .dropStmt = delq->data));
   11300             : 
   11301             :     /* Dump Type Comments and Security Labels */
   11302         184 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11303          78 :         dumpComment(fout, "TYPE", qtypname,
   11304          78 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11305             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11306             : 
   11307         184 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11308           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11309           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11310             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11311             : 
   11312         184 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11313          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11314             :                 qtypname, NULL,
   11315          66 :                 tyinfo->dobj.namespace->dobj.name,
   11316             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11317             : 
   11318         184 :     PQclear(res);
   11319         184 :     destroyPQExpBuffer(q);
   11320         184 :     destroyPQExpBuffer(delq);
   11321         184 :     destroyPQExpBuffer(query);
   11322         184 :     free(qtypname);
   11323         184 :     free(qualtypname);
   11324         184 : }
   11325             : 
   11326             : /*
   11327             :  * dumpUndefinedType
   11328             :  *    writes out to fout the queries to recreate a !typisdefined type
   11329             :  *
   11330             :  * This is a shell type, but we use different terminology to distinguish
   11331             :  * this case from where we have to emit a shell type definition to break
   11332             :  * circular dependencies.  An undefined type shouldn't ever have anything
   11333             :  * depending on it.
   11334             :  */
   11335             : static void
   11336          76 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   11337             : {
   11338          76 :     DumpOptions *dopt = fout->dopt;
   11339          76 :     PQExpBuffer q = createPQExpBuffer();
   11340          76 :     PQExpBuffer delq = createPQExpBuffer();
   11341             :     char       *qtypname;
   11342             :     char       *qualtypname;
   11343             : 
   11344          76 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11345          76 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11346             : 
   11347          76 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11348             : 
   11349          76 :     if (dopt->binary_upgrade)
   11350           4 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11351             :                                                  tyinfo->dobj.catId.oid,
   11352             :                                                  false, false);
   11353             : 
   11354          76 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   11355             :                       qualtypname);
   11356             : 
   11357          76 :     if (dopt->binary_upgrade)
   11358           4 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11359             :                                         "TYPE", qtypname,
   11360           4 :                                         tyinfo->dobj.namespace->dobj.name);
   11361             : 
   11362          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11363          76 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11364          76 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11365             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11366             :                                   .owner = tyinfo->rolname,
   11367             :                                   .description = "TYPE",
   11368             :                                   .section = SECTION_PRE_DATA,
   11369             :                                   .createStmt = q->data,
   11370             :                                   .dropStmt = delq->data));
   11371             : 
   11372             :     /* Dump Type Comments and Security Labels */
   11373          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11374          66 :         dumpComment(fout, "TYPE", qtypname,
   11375          66 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11376             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11377             : 
   11378          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11379           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11380           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11381             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11382             : 
   11383          76 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11384           0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11385             :                 qtypname, NULL,
   11386           0 :                 tyinfo->dobj.namespace->dobj.name,
   11387             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11388             : 
   11389          76 :     destroyPQExpBuffer(q);
   11390          76 :     destroyPQExpBuffer(delq);
   11391          76 :     free(qtypname);
   11392          76 :     free(qualtypname);
   11393          76 : }
   11394             : 
   11395             : /*
   11396             :  * dumpBaseType
   11397             :  *    writes out to fout the queries to recreate a user-defined base type
   11398             :  */
   11399             : static void
   11400         276 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   11401             : {
   11402         276 :     DumpOptions *dopt = fout->dopt;
   11403         276 :     PQExpBuffer q = createPQExpBuffer();
   11404         276 :     PQExpBuffer delq = createPQExpBuffer();
   11405         276 :     PQExpBuffer query = createPQExpBuffer();
   11406             :     PGresult   *res;
   11407             :     char       *qtypname;
   11408             :     char       *qualtypname;
   11409             :     char       *typlen;
   11410             :     char       *typinput;
   11411             :     char       *typoutput;
   11412             :     char       *typreceive;
   11413             :     char       *typsend;
   11414             :     char       *typmodin;
   11415             :     char       *typmodout;
   11416             :     char       *typanalyze;
   11417             :     char       *typsubscript;
   11418             :     Oid         typreceiveoid;
   11419             :     Oid         typsendoid;
   11420             :     Oid         typmodinoid;
   11421             :     Oid         typmodoutoid;
   11422             :     Oid         typanalyzeoid;
   11423             :     Oid         typsubscriptoid;
   11424             :     char       *typcategory;
   11425             :     char       *typispreferred;
   11426             :     char       *typdelim;
   11427             :     char       *typbyval;
   11428             :     char       *typalign;
   11429             :     char       *typstorage;
   11430             :     char       *typcollatable;
   11431             :     char       *typdefault;
   11432         276 :     bool        typdefault_is_literal = false;
   11433             : 
   11434         276 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   11435             :     {
   11436             :         /* Set up query for type-specific details */
   11437          78 :         appendPQExpBufferStr(query,
   11438             :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   11439             :                              "SELECT typlen, "
   11440             :                              "typinput, typoutput, typreceive, typsend, "
   11441             :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   11442             :                              "typsend::pg_catalog.oid AS typsendoid, "
   11443             :                              "typanalyze, "
   11444             :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   11445             :                              "typdelim, typbyval, typalign, typstorage, "
   11446             :                              "typmodin, typmodout, "
   11447             :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   11448             :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   11449             :                              "typcategory, typispreferred, "
   11450             :                              "(typcollation <> 0) AS typcollatable, "
   11451             :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   11452             : 
   11453          78 :         if (fout->remoteVersion >= 140000)
   11454          78 :             appendPQExpBufferStr(query,
   11455             :                                  "typsubscript, "
   11456             :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   11457             :         else
   11458           0 :             appendPQExpBufferStr(query,
   11459             :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   11460             : 
   11461          78 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   11462             :                              "WHERE oid = $1");
   11463             : 
   11464          78 :         ExecuteSqlStatement(fout, query->data);
   11465             : 
   11466          78 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   11467             :     }
   11468             : 
   11469         276 :     printfPQExpBuffer(query,
   11470             :                       "EXECUTE dumpBaseType('%u')",
   11471             :                       tyinfo->dobj.catId.oid);
   11472             : 
   11473         276 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11474             : 
   11475         276 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   11476         276 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   11477         276 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   11478         276 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   11479         276 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   11480         276 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   11481         276 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   11482         276 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   11483         276 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   11484         276 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   11485         276 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   11486         276 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   11487         276 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   11488         276 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   11489         276 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   11490         276 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   11491         276 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   11492         276 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   11493         276 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   11494         276 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   11495         276 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   11496         276 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   11497         276 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   11498           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   11499         276 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   11500             :     {
   11501          86 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   11502          86 :         typdefault_is_literal = true;   /* it needs quotes */
   11503             :     }
   11504             :     else
   11505         190 :         typdefault = NULL;
   11506             : 
   11507         276 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11508         276 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11509             : 
   11510             :     /*
   11511             :      * The reason we include CASCADE is that the circular dependency between
   11512             :      * the type and its I/O functions makes it impossible to drop the type any
   11513             :      * other way.
   11514             :      */
   11515         276 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   11516             : 
   11517             :     /*
   11518             :      * We might already have a shell type, but setting pg_type_oid is
   11519             :      * harmless, and in any case we'd better set the array type OID.
   11520             :      */
   11521         276 :     if (dopt->binary_upgrade)
   11522          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11523             :                                                  tyinfo->dobj.catId.oid,
   11524             :                                                  false, false);
   11525             : 
   11526         276 :     appendPQExpBuffer(q,
   11527             :                       "CREATE TYPE %s (\n"
   11528             :                       "    INTERNALLENGTH = %s",
   11529             :                       qualtypname,
   11530         276 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   11531             : 
   11532             :     /* regproc result is sufficiently quoted already */
   11533         276 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   11534         276 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   11535         276 :     if (OidIsValid(typreceiveoid))
   11536         136 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   11537         276 :     if (OidIsValid(typsendoid))
   11538         136 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   11539         276 :     if (OidIsValid(typmodinoid))
   11540          30 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   11541         276 :     if (OidIsValid(typmodoutoid))
   11542          30 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   11543         276 :     if (OidIsValid(typanalyzeoid))
   11544           2 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   11545             : 
   11546         276 :     if (strcmp(typcollatable, "t") == 0)
   11547          20 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   11548             : 
   11549         276 :     if (typdefault != NULL)
   11550             :     {
   11551          86 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   11552          86 :         if (typdefault_is_literal)
   11553          86 :             appendStringLiteralAH(q, typdefault, fout);
   11554             :         else
   11555           0 :             appendPQExpBufferStr(q, typdefault);
   11556             :     }
   11557             : 
   11558         276 :     if (OidIsValid(typsubscriptoid))
   11559          26 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   11560             : 
   11561         276 :     if (OidIsValid(tyinfo->typelem))
   11562          24 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   11563             :                           getFormattedTypeName(fout, tyinfo->typelem,
   11564             :                                                zeroIsError));
   11565             : 
   11566         276 :     if (strcmp(typcategory, "U") != 0)
   11567             :     {
   11568         110 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   11569         110 :         appendStringLiteralAH(q, typcategory, fout);
   11570             :     }
   11571             : 
   11572         276 :     if (strcmp(typispreferred, "t") == 0)
   11573          26 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   11574             : 
   11575         276 :     if (typdelim && strcmp(typdelim, ",") != 0)
   11576             :     {
   11577           2 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   11578           2 :         appendStringLiteralAH(q, typdelim, fout);
   11579             :     }
   11580             : 
   11581         276 :     if (*typalign == TYPALIGN_CHAR)
   11582           8 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   11583         268 :     else if (*typalign == TYPALIGN_SHORT)
   11584           4 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   11585         264 :     else if (*typalign == TYPALIGN_INT)
   11586         194 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   11587          70 :     else if (*typalign == TYPALIGN_DOUBLE)
   11588          70 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   11589             : 
   11590         276 :     if (*typstorage == TYPSTORAGE_PLAIN)
   11591         226 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   11592          50 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   11593           0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   11594          50 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   11595          44 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   11596           6 :     else if (*typstorage == TYPSTORAGE_MAIN)
   11597           6 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   11598             : 
   11599         276 :     if (strcmp(typbyval, "t") == 0)
   11600         152 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   11601             : 
   11602         276 :     appendPQExpBufferStr(q, "\n);\n");
   11603             : 
   11604         276 :     if (dopt->binary_upgrade)
   11605          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11606             :                                         "TYPE", qtypname,
   11607          16 :                                         tyinfo->dobj.namespace->dobj.name);
   11608             : 
   11609         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11610         276 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11611         276 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11612             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11613             :                                   .owner = tyinfo->rolname,
   11614             :                                   .description = "TYPE",
   11615             :                                   .section = SECTION_PRE_DATA,
   11616             :                                   .createStmt = q->data,
   11617             :                                   .dropStmt = delq->data));
   11618             : 
   11619             :     /* Dump Type Comments and Security Labels */
   11620         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11621         206 :         dumpComment(fout, "TYPE", qtypname,
   11622         206 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11623             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11624             : 
   11625         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11626           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11627           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11628             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11629             : 
   11630         276 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11631          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11632             :                 qtypname, NULL,
   11633          66 :                 tyinfo->dobj.namespace->dobj.name,
   11634             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11635             : 
   11636         276 :     PQclear(res);
   11637         276 :     destroyPQExpBuffer(q);
   11638         276 :     destroyPQExpBuffer(delq);
   11639         276 :     destroyPQExpBuffer(query);
   11640         276 :     free(qtypname);
   11641         276 :     free(qualtypname);
   11642         276 : }
   11643             : 
   11644             : /*
   11645             :  * dumpDomain
   11646             :  *    writes out to fout the queries to recreate a user-defined domain
   11647             :  */
   11648             : static void
   11649         256 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   11650             : {
   11651         256 :     DumpOptions *dopt = fout->dopt;
   11652         256 :     PQExpBuffer q = createPQExpBuffer();
   11653         256 :     PQExpBuffer delq = createPQExpBuffer();
   11654         256 :     PQExpBuffer query = createPQExpBuffer();
   11655             :     PGresult   *res;
   11656             :     int         i;
   11657             :     char       *qtypname;
   11658             :     char       *qualtypname;
   11659             :     char       *typnotnull;
   11660             :     char       *typdefn;
   11661             :     char       *typdefault;
   11662             :     Oid         typcollation;
   11663         256 :     bool        typdefault_is_literal = false;
   11664             : 
   11665         256 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   11666             :     {
   11667             :         /* Set up query for domain-specific details */
   11668          76 :         appendPQExpBufferStr(query,
   11669             :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   11670             : 
   11671          76 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   11672             :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   11673             :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   11674             :                              "t.typdefault, "
   11675             :                              "CASE WHEN t.typcollation <> u.typcollation "
   11676             :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   11677             :                              "FROM pg_catalog.pg_type t "
   11678             :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   11679             :                              "WHERE t.oid = $1");
   11680             : 
   11681          76 :         ExecuteSqlStatement(fout, query->data);
   11682             : 
   11683          76 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   11684             :     }
   11685             : 
   11686         256 :     printfPQExpBuffer(query,
   11687             :                       "EXECUTE dumpDomain('%u')",
   11688             :                       tyinfo->dobj.catId.oid);
   11689             : 
   11690         256 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11691             : 
   11692         256 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   11693         256 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   11694         256 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   11695          76 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   11696         180 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   11697             :     {
   11698           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   11699           0 :         typdefault_is_literal = true;   /* it needs quotes */
   11700             :     }
   11701             :     else
   11702         180 :         typdefault = NULL;
   11703         256 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   11704             : 
   11705         256 :     if (dopt->binary_upgrade)
   11706          40 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11707             :                                                  tyinfo->dobj.catId.oid,
   11708             :                                                  true,  /* force array type */
   11709             :                                                  false);    /* force multirange type */
   11710             : 
   11711         256 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11712         256 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11713             : 
   11714         256 :     appendPQExpBuffer(q,
   11715             :                       "CREATE DOMAIN %s AS %s",
   11716             :                       qualtypname,
   11717             :                       typdefn);
   11718             : 
   11719             :     /* Print collation only if different from base type's collation */
   11720         256 :     if (OidIsValid(typcollation))
   11721             :     {
   11722             :         CollInfo   *coll;
   11723             : 
   11724          66 :         coll = findCollationByOid(typcollation);
   11725          66 :         if (coll)
   11726          66 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   11727             :     }
   11728             : 
   11729         256 :     if (typnotnull[0] == 't')
   11730          30 :         appendPQExpBufferStr(q, " NOT NULL");
   11731             : 
   11732         256 :     if (typdefault != NULL)
   11733             :     {
   11734          76 :         appendPQExpBufferStr(q, " DEFAULT ");
   11735          76 :         if (typdefault_is_literal)
   11736           0 :             appendStringLiteralAH(q, typdefault, fout);
   11737             :         else
   11738          76 :             appendPQExpBufferStr(q, typdefault);
   11739             :     }
   11740             : 
   11741         256 :     PQclear(res);
   11742             : 
   11743             :     /*
   11744             :      * Add any CHECK constraints for the domain
   11745             :      */
   11746         422 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   11747             :     {
   11748         166 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   11749             : 
   11750         166 :         if (!domcheck->separate)
   11751         166 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   11752         166 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   11753             :     }
   11754             : 
   11755         256 :     appendPQExpBufferStr(q, ";\n");
   11756             : 
   11757         256 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   11758             : 
   11759         256 :     if (dopt->binary_upgrade)
   11760          40 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11761             :                                         "DOMAIN", qtypname,
   11762          40 :                                         tyinfo->dobj.namespace->dobj.name);
   11763             : 
   11764         256 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11765         256 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11766         256 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11767             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11768             :                                   .owner = tyinfo->rolname,
   11769             :                                   .description = "DOMAIN",
   11770             :                                   .section = SECTION_PRE_DATA,
   11771             :                                   .createStmt = q->data,
   11772             :                                   .dropStmt = delq->data));
   11773             : 
   11774             :     /* Dump Domain Comments and Security Labels */
   11775         256 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11776           0 :         dumpComment(fout, "DOMAIN", qtypname,
   11777           0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11778             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11779             : 
   11780         256 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11781           0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   11782           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11783             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11784             : 
   11785         256 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11786          66 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11787             :                 qtypname, NULL,
   11788          66 :                 tyinfo->dobj.namespace->dobj.name,
   11789             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11790             : 
   11791             :     /* Dump any per-constraint comments */
   11792         422 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   11793             :     {
   11794         166 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   11795         166 :         PQExpBuffer conprefix = createPQExpBuffer();
   11796             : 
   11797         166 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   11798         166 :                           fmtId(domcheck->dobj.name));
   11799             : 
   11800         166 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   11801          66 :             dumpComment(fout, conprefix->data, qtypname,
   11802          66 :                         tyinfo->dobj.namespace->dobj.name,
   11803             :                         tyinfo->rolname,
   11804             :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   11805             : 
   11806         166 :         destroyPQExpBuffer(conprefix);
   11807             :     }
   11808             : 
   11809         256 :     destroyPQExpBuffer(q);
   11810         256 :     destroyPQExpBuffer(delq);
   11811         256 :     destroyPQExpBuffer(query);
   11812         256 :     free(qtypname);
   11813         256 :     free(qualtypname);
   11814         256 : }
   11815             : 
   11816             : /*
   11817             :  * dumpCompositeType
   11818             :  *    writes out to fout the queries to recreate a user-defined stand-alone
   11819             :  *    composite type
   11820             :  */
   11821             : static void
   11822         262 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   11823             : {
   11824         262 :     DumpOptions *dopt = fout->dopt;
   11825         262 :     PQExpBuffer q = createPQExpBuffer();
   11826         262 :     PQExpBuffer dropped = createPQExpBuffer();
   11827         262 :     PQExpBuffer delq = createPQExpBuffer();
   11828         262 :     PQExpBuffer query = createPQExpBuffer();
   11829             :     PGresult   *res;
   11830             :     char       *qtypname;
   11831             :     char       *qualtypname;
   11832             :     int         ntups;
   11833             :     int         i_attname;
   11834             :     int         i_atttypdefn;
   11835             :     int         i_attlen;
   11836             :     int         i_attalign;
   11837             :     int         i_attisdropped;
   11838             :     int         i_attcollation;
   11839             :     int         i;
   11840             :     int         actual_atts;
   11841             : 
   11842         262 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   11843             :     {
   11844             :         /*
   11845             :          * Set up query for type-specific details.
   11846             :          *
   11847             :          * Since we only want to dump COLLATE clauses for attributes whose
   11848             :          * collation is different from their type's default, we use a CASE
   11849             :          * here to suppress uninteresting attcollations cheaply.  atttypid
   11850             :          * will be 0 for dropped columns; collation does not matter for those.
   11851             :          */
   11852         112 :         appendPQExpBufferStr(query,
   11853             :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   11854             :                              "SELECT a.attname, a.attnum, "
   11855             :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   11856             :                              "a.attlen, a.attalign, a.attisdropped, "
   11857             :                              "CASE WHEN a.attcollation <> at.typcollation "
   11858             :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   11859             :                              "FROM pg_catalog.pg_type ct "
   11860             :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   11861             :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   11862             :                              "WHERE ct.oid = $1 "
   11863             :                              "ORDER BY a.attnum");
   11864             : 
   11865         112 :         ExecuteSqlStatement(fout, query->data);
   11866             : 
   11867         112 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   11868             :     }
   11869             : 
   11870         262 :     printfPQExpBuffer(query,
   11871             :                       "EXECUTE dumpCompositeType('%u')",
   11872             :                       tyinfo->dobj.catId.oid);
   11873             : 
   11874         262 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11875             : 
   11876         262 :     ntups = PQntuples(res);
   11877             : 
   11878         262 :     i_attname = PQfnumber(res, "attname");
   11879         262 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   11880         262 :     i_attlen = PQfnumber(res, "attlen");
   11881         262 :     i_attalign = PQfnumber(res, "attalign");
   11882         262 :     i_attisdropped = PQfnumber(res, "attisdropped");
   11883         262 :     i_attcollation = PQfnumber(res, "attcollation");
   11884             : 
   11885         262 :     if (dopt->binary_upgrade)
   11886             :     {
   11887          36 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11888             :                                                  tyinfo->dobj.catId.oid,
   11889             :                                                  false, false);
   11890          36 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
   11891             :     }
   11892             : 
   11893         262 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11894         262 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11895             : 
   11896         262 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   11897             :                       qualtypname);
   11898             : 
   11899         262 :     actual_atts = 0;
   11900         830 :     for (i = 0; i < ntups; i++)
   11901             :     {
   11902             :         char       *attname;
   11903             :         char       *atttypdefn;
   11904             :         char       *attlen;
   11905             :         char       *attalign;
   11906             :         bool        attisdropped;
   11907             :         Oid         attcollation;
   11908             : 
   11909         568 :         attname = PQgetvalue(res, i, i_attname);
   11910         568 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   11911         568 :         attlen = PQgetvalue(res, i, i_attlen);
   11912         568 :         attalign = PQgetvalue(res, i, i_attalign);
   11913         568 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   11914         568 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   11915             : 
   11916         568 :         if (attisdropped && !dopt->binary_upgrade)
   11917          16 :             continue;
   11918             : 
   11919             :         /* Format properly if not first attr */
   11920         552 :         if (actual_atts++ > 0)
   11921         290 :             appendPQExpBufferChar(q, ',');
   11922         552 :         appendPQExpBufferStr(q, "\n\t");
   11923             : 
   11924         552 :         if (!attisdropped)
   11925             :         {
   11926         548 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   11927             : 
   11928             :             /* Add collation if not default for the column type */
   11929         548 :             if (OidIsValid(attcollation))
   11930             :             {
   11931             :                 CollInfo   *coll;
   11932             : 
   11933           0 :                 coll = findCollationByOid(attcollation);
   11934           0 :                 if (coll)
   11935           0 :                     appendPQExpBuffer(q, " COLLATE %s",
   11936           0 :                                       fmtQualifiedDumpable(coll));
   11937             :             }
   11938             :         }
   11939             :         else
   11940             :         {
   11941             :             /*
   11942             :              * This is a dropped attribute and we're in binary_upgrade mode.
   11943             :              * Insert a placeholder for it in the CREATE TYPE command, and set
   11944             :              * length and alignment with direct UPDATE to the catalogs
   11945             :              * afterwards. See similar code in dumpTableSchema().
   11946             :              */
   11947           4 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   11948             : 
   11949             :             /* stash separately for insertion after the CREATE TYPE */
   11950           4 :             appendPQExpBufferStr(dropped,
   11951             :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   11952           4 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   11953             :                               "SET attlen = %s, "
   11954             :                               "attalign = '%s', attbyval = false\n"
   11955             :                               "WHERE attname = ", attlen, attalign);
   11956           4 :             appendStringLiteralAH(dropped, attname, fout);
   11957           4 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   11958           4 :             appendStringLiteralAH(dropped, qualtypname, fout);
   11959           4 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   11960             : 
   11961           4 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   11962             :                               qualtypname);
   11963           4 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   11964             :                               fmtId(attname));
   11965             :         }
   11966             :     }
   11967         262 :     appendPQExpBufferStr(q, "\n);\n");
   11968         262 :     appendPQExpBufferStr(q, dropped->data);
   11969             : 
   11970         262 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11971             : 
   11972         262 :     if (dopt->binary_upgrade)
   11973          36 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11974             :                                         "TYPE", qtypname,
   11975          36 :                                         tyinfo->dobj.namespace->dobj.name);
   11976             : 
   11977         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11978         228 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11979         228 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11980             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11981             :                                   .owner = tyinfo->rolname,
   11982             :                                   .description = "TYPE",
   11983             :                                   .section = SECTION_PRE_DATA,
   11984             :                                   .createStmt = q->data,
   11985             :                                   .dropStmt = delq->data));
   11986             : 
   11987             : 
   11988             :     /* Dump Type Comments and Security Labels */
   11989         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11990          66 :         dumpComment(fout, "TYPE", qtypname,
   11991          66 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11992             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11993             : 
   11994         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11995           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11996           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11997             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11998             : 
   11999         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12000          36 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12001             :                 qtypname, NULL,
   12002          36 :                 tyinfo->dobj.namespace->dobj.name,
   12003             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12004             : 
   12005             :     /* Dump any per-column comments */
   12006         262 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12007          66 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   12008             : 
   12009         262 :     PQclear(res);
   12010         262 :     destroyPQExpBuffer(q);
   12011         262 :     destroyPQExpBuffer(dropped);
   12012         262 :     destroyPQExpBuffer(delq);
   12013         262 :     destroyPQExpBuffer(query);
   12014         262 :     free(qtypname);
   12015         262 :     free(qualtypname);
   12016         262 : }
   12017             : 
   12018             : /*
   12019             :  * dumpCompositeTypeColComments
   12020             :  *    writes out to fout the queries to recreate comments on the columns of
   12021             :  *    a user-defined stand-alone composite type.
   12022             :  *
   12023             :  * The caller has already made a query to collect the names and attnums
   12024             :  * of the type's columns, so we just pass that result into here rather
   12025             :  * than reading them again.
   12026             :  */
   12027             : static void
   12028          66 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   12029             :                              PGresult *res)
   12030             : {
   12031             :     CommentItem *comments;
   12032             :     int         ncomments;
   12033             :     PQExpBuffer query;
   12034             :     PQExpBuffer target;
   12035             :     int         i;
   12036             :     int         ntups;
   12037             :     int         i_attname;
   12038             :     int         i_attnum;
   12039             :     int         i_attisdropped;
   12040             : 
   12041             :     /* do nothing, if --no-comments is supplied */
   12042          66 :     if (fout->dopt->no_comments)
   12043           0 :         return;
   12044             : 
   12045             :     /* Search for comments associated with type's pg_class OID */
   12046          66 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   12047             :                              &comments);
   12048             : 
   12049             :     /* If no comments exist, we're done */
   12050          66 :     if (ncomments <= 0)
   12051           0 :         return;
   12052             : 
   12053             :     /* Build COMMENT ON statements */
   12054          66 :     query = createPQExpBuffer();
   12055          66 :     target = createPQExpBuffer();
   12056             : 
   12057          66 :     ntups = PQntuples(res);
   12058          66 :     i_attnum = PQfnumber(res, "attnum");
   12059          66 :     i_attname = PQfnumber(res, "attname");
   12060          66 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12061         132 :     while (ncomments > 0)
   12062             :     {
   12063             :         const char *attname;
   12064             : 
   12065          66 :         attname = NULL;
   12066          66 :         for (i = 0; i < ntups; i++)
   12067             :         {
   12068          66 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   12069          66 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   12070             :             {
   12071          66 :                 attname = PQgetvalue(res, i, i_attname);
   12072          66 :                 break;
   12073             :             }
   12074             :         }
   12075          66 :         if (attname)            /* just in case we don't find it */
   12076             :         {
   12077          66 :             const char *descr = comments->descr;
   12078             : 
   12079          66 :             resetPQExpBuffer(target);
   12080          66 :             appendPQExpBuffer(target, "COLUMN %s.",
   12081          66 :                               fmtId(tyinfo->dobj.name));
   12082          66 :             appendPQExpBufferStr(target, fmtId(attname));
   12083             : 
   12084          66 :             resetPQExpBuffer(query);
   12085          66 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   12086          66 :                               fmtQualifiedDumpable(tyinfo));
   12087          66 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   12088          66 :             appendStringLiteralAH(query, descr, fout);
   12089          66 :             appendPQExpBufferStr(query, ";\n");
   12090             : 
   12091          66 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   12092          66 :                          ARCHIVE_OPTS(.tag = target->data,
   12093             :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   12094             :                                       .owner = tyinfo->rolname,
   12095             :                                       .description = "COMMENT",
   12096             :                                       .section = SECTION_NONE,
   12097             :                                       .createStmt = query->data,
   12098             :                                       .deps = &(tyinfo->dobj.dumpId),
   12099             :                                       .nDeps = 1));
   12100             :         }
   12101             : 
   12102          66 :         comments++;
   12103          66 :         ncomments--;
   12104             :     }
   12105             : 
   12106          66 :     destroyPQExpBuffer(query);
   12107          66 :     destroyPQExpBuffer(target);
   12108             : }
   12109             : 
   12110             : /*
   12111             :  * dumpShellType
   12112             :  *    writes out to fout the queries to create a shell type
   12113             :  *
   12114             :  * We dump a shell definition in advance of the I/O functions for the type.
   12115             :  */
   12116             : static void
   12117         142 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   12118             : {
   12119         142 :     DumpOptions *dopt = fout->dopt;
   12120             :     PQExpBuffer q;
   12121             : 
   12122             :     /* Do nothing in data-only dump */
   12123         142 :     if (dopt->dataOnly)
   12124           6 :         return;
   12125             : 
   12126         136 :     q = createPQExpBuffer();
   12127             : 
   12128             :     /*
   12129             :      * Note the lack of a DROP command for the shell type; any required DROP
   12130             :      * is driven off the base type entry, instead.  This interacts with
   12131             :      * _printTocEntry()'s use of the presence of a DROP command to decide
   12132             :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   12133             :      * the shell type's owner immediately on creation; that should happen only
   12134             :      * after it's filled in, otherwise the backend complains.
   12135             :      */
   12136             : 
   12137         136 :     if (dopt->binary_upgrade)
   12138          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12139          16 :                                                  stinfo->baseType->dobj.catId.oid,
   12140             :                                                  false, false);
   12141             : 
   12142         136 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12143         136 :                       fmtQualifiedDumpable(stinfo));
   12144             : 
   12145         136 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12146         136 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   12147         136 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   12148             :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   12149             :                                   .owner = stinfo->baseType->rolname,
   12150             :                                   .description = "SHELL TYPE",
   12151             :                                   .section = SECTION_PRE_DATA,
   12152             :                                   .createStmt = q->data));
   12153             : 
   12154         136 :     destroyPQExpBuffer(q);
   12155             : }
   12156             : 
   12157             : /*
   12158             :  * dumpProcLang
   12159             :  *        writes out to fout the queries to recreate a user-defined
   12160             :  *        procedural language
   12161             :  */
   12162             : static void
   12163         156 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   12164             : {
   12165         156 :     DumpOptions *dopt = fout->dopt;
   12166             :     PQExpBuffer defqry;
   12167             :     PQExpBuffer delqry;
   12168             :     bool        useParams;
   12169             :     char       *qlanname;
   12170             :     FuncInfo   *funcInfo;
   12171         156 :     FuncInfo   *inlineInfo = NULL;
   12172         156 :     FuncInfo   *validatorInfo = NULL;
   12173             : 
   12174             :     /* Do nothing in data-only dump */
   12175         156 :     if (dopt->dataOnly)
   12176          14 :         return;
   12177             : 
   12178             :     /*
   12179             :      * Try to find the support function(s).  It is not an error if we don't
   12180             :      * find them --- if the functions are in the pg_catalog schema, as is
   12181             :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   12182             :      * we will emit a parameterless CREATE LANGUAGE command, which will
   12183             :      * require PL template knowledge in the backend to reload.)
   12184             :      */
   12185             : 
   12186         142 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   12187         142 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   12188           4 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   12189             : 
   12190         142 :     if (OidIsValid(plang->laninline))
   12191             :     {
   12192          78 :         inlineInfo = findFuncByOid(plang->laninline);
   12193          78 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   12194           2 :             inlineInfo = NULL;
   12195             :     }
   12196             : 
   12197         142 :     if (OidIsValid(plang->lanvalidator))
   12198             :     {
   12199          78 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   12200          78 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   12201           2 :             validatorInfo = NULL;
   12202             :     }
   12203             : 
   12204             :     /*
   12205             :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   12206             :      * parameters.  Otherwise, we'll write a parameterless command, which will
   12207             :      * be interpreted as CREATE EXTENSION.
   12208             :      */
   12209          62 :     useParams = (funcInfo != NULL &&
   12210         266 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   12211          62 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   12212             : 
   12213         142 :     defqry = createPQExpBuffer();
   12214         142 :     delqry = createPQExpBuffer();
   12215             : 
   12216         142 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   12217             : 
   12218         142 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   12219             :                       qlanname);
   12220             : 
   12221         142 :     if (useParams)
   12222             :     {
   12223          62 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   12224          62 :                           plang->lanpltrusted ? "TRUSTED " : "",
   12225             :                           qlanname);
   12226          62 :         appendPQExpBuffer(defqry, " HANDLER %s",
   12227          62 :                           fmtQualifiedDumpable(funcInfo));
   12228          62 :         if (OidIsValid(plang->laninline))
   12229           0 :             appendPQExpBuffer(defqry, " INLINE %s",
   12230           0 :                               fmtQualifiedDumpable(inlineInfo));
   12231          62 :         if (OidIsValid(plang->lanvalidator))
   12232           0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   12233           0 :                               fmtQualifiedDumpable(validatorInfo));
   12234             :     }
   12235             :     else
   12236             :     {
   12237             :         /*
   12238             :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   12239             :          * command will not fail if the language is preinstalled in the target
   12240             :          * database.
   12241             :          *
   12242             :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   12243             :          * EXISTS; perhaps we should emit that instead?  But it might just add
   12244             :          * confusion.
   12245             :          */
   12246          80 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   12247             :                           qlanname);
   12248             :     }
   12249         142 :     appendPQExpBufferStr(defqry, ";\n");
   12250             : 
   12251         142 :     if (dopt->binary_upgrade)
   12252           4 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   12253             :                                         "LANGUAGE", qlanname, NULL);
   12254             : 
   12255         142 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12256          64 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   12257          64 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   12258             :                                   .owner = plang->lanowner,
   12259             :                                   .description = "PROCEDURAL LANGUAGE",
   12260             :                                   .section = SECTION_PRE_DATA,
   12261             :                                   .createStmt = defqry->data,
   12262             :                                   .dropStmt = delqry->data,
   12263             :                                   ));
   12264             : 
   12265             :     /* Dump Proc Lang Comments and Security Labels */
   12266         142 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   12267           0 :         dumpComment(fout, "LANGUAGE", qlanname,
   12268             :                     NULL, plang->lanowner,
   12269             :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   12270             : 
   12271         142 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12272           0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   12273             :                      NULL, plang->lanowner,
   12274             :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   12275             : 
   12276         142 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   12277          78 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   12278             :                 qlanname, NULL, NULL,
   12279             :                 NULL, plang->lanowner, &plang->dacl);
   12280             : 
   12281         142 :     free(qlanname);
   12282             : 
   12283         142 :     destroyPQExpBuffer(defqry);
   12284         142 :     destroyPQExpBuffer(delqry);
   12285             : }
   12286             : 
   12287             : /*
   12288             :  * format_function_arguments: generate function name and argument list
   12289             :  *
   12290             :  * This is used when we can rely on pg_get_function_arguments to format
   12291             :  * the argument list.  Note, however, that pg_get_function_arguments
   12292             :  * does not special-case zero-argument aggregates.
   12293             :  */
   12294             : static char *
   12295        8052 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   12296             : {
   12297             :     PQExpBufferData fn;
   12298             : 
   12299        8052 :     initPQExpBuffer(&fn);
   12300        8052 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   12301        8052 :     if (is_agg && finfo->nargs == 0)
   12302         160 :         appendPQExpBufferStr(&fn, "(*)");
   12303             :     else
   12304        7892 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   12305        8052 :     return fn.data;
   12306             : }
   12307             : 
   12308             : /*
   12309             :  * format_function_signature: generate function name and argument list
   12310             :  *
   12311             :  * Only a minimal list of input argument types is generated; this is
   12312             :  * sufficient to reference the function, but not to define it.
   12313             :  *
   12314             :  * If honor_quotes is false then the function name is never quoted.
   12315             :  * This is appropriate for use in TOC tags, but not in SQL commands.
   12316             :  */
   12317             : static char *
   12318        4248 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   12319             : {
   12320             :     PQExpBufferData fn;
   12321             :     int         j;
   12322             : 
   12323        4248 :     initPQExpBuffer(&fn);
   12324        4248 :     if (honor_quotes)
   12325         794 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   12326             :     else
   12327        3454 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   12328        7808 :     for (j = 0; j < finfo->nargs; j++)
   12329             :     {
   12330        3560 :         if (j > 0)
   12331         834 :             appendPQExpBufferStr(&fn, ", ");
   12332             : 
   12333        3560 :         appendPQExpBufferStr(&fn,
   12334        3560 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   12335             :                                                   zeroIsError));
   12336             :     }
   12337        4248 :     appendPQExpBufferChar(&fn, ')');
   12338        4248 :     return fn.data;
   12339             : }
   12340             : 
   12341             : 
   12342             : /*
   12343             :  * dumpFunc:
   12344             :  *    dump out one function
   12345             :  */
   12346             : static void
   12347        3518 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   12348             : {
   12349        3518 :     DumpOptions *dopt = fout->dopt;
   12350             :     PQExpBuffer query;
   12351             :     PQExpBuffer q;
   12352             :     PQExpBuffer delqry;
   12353             :     PQExpBuffer asPart;
   12354             :     PGresult   *res;
   12355             :     char       *funcsig;        /* identity signature */
   12356        3518 :     char       *funcfullsig = NULL; /* full signature */
   12357             :     char       *funcsig_tag;
   12358             :     char       *qual_funcsig;
   12359             :     char       *proretset;
   12360             :     char       *prosrc;
   12361             :     char       *probin;
   12362             :     char       *prosqlbody;
   12363             :     char       *funcargs;
   12364             :     char       *funciargs;
   12365             :     char       *funcresult;
   12366             :     char       *protrftypes;
   12367             :     char       *prokind;
   12368             :     char       *provolatile;
   12369             :     char       *proisstrict;
   12370             :     char       *prosecdef;
   12371             :     char       *proleakproof;
   12372             :     char       *proconfig;
   12373             :     char       *procost;
   12374             :     char       *prorows;
   12375             :     char       *prosupport;
   12376             :     char       *proparallel;
   12377             :     char       *lanname;
   12378        3518 :     char      **configitems = NULL;
   12379        3518 :     int         nconfigitems = 0;
   12380             :     const char *keyword;
   12381             : 
   12382             :     /* Do nothing in data-only dump */
   12383        3518 :     if (dopt->dataOnly)
   12384          64 :         return;
   12385             : 
   12386        3454 :     query = createPQExpBuffer();
   12387        3454 :     q = createPQExpBuffer();
   12388        3454 :     delqry = createPQExpBuffer();
   12389        3454 :     asPart = createPQExpBuffer();
   12390             : 
   12391        3454 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   12392             :     {
   12393             :         /* Set up query for function-specific details */
   12394         120 :         appendPQExpBufferStr(query,
   12395             :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   12396             : 
   12397         120 :         appendPQExpBufferStr(query,
   12398             :                              "SELECT\n"
   12399             :                              "proretset,\n"
   12400             :                              "prosrc,\n"
   12401             :                              "probin,\n"
   12402             :                              "provolatile,\n"
   12403             :                              "proisstrict,\n"
   12404             :                              "prosecdef,\n"
   12405             :                              "lanname,\n"
   12406             :                              "proconfig,\n"
   12407             :                              "procost,\n"
   12408             :                              "prorows,\n"
   12409             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   12410             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   12411             :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   12412             :                              "proleakproof,\n");
   12413             : 
   12414         120 :         if (fout->remoteVersion >= 90500)
   12415         120 :             appendPQExpBufferStr(query,
   12416             :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   12417             :         else
   12418           0 :             appendPQExpBufferStr(query,
   12419             :                                  "NULL AS protrftypes,\n");
   12420             : 
   12421         120 :         if (fout->remoteVersion >= 90600)
   12422         120 :             appendPQExpBufferStr(query,
   12423             :                                  "proparallel,\n");
   12424             :         else
   12425           0 :             appendPQExpBufferStr(query,
   12426             :                                  "'u' AS proparallel,\n");
   12427             : 
   12428         120 :         if (fout->remoteVersion >= 110000)
   12429         120 :             appendPQExpBufferStr(query,
   12430             :                                  "prokind,\n");
   12431             :         else
   12432           0 :             appendPQExpBufferStr(query,
   12433             :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   12434             : 
   12435         120 :         if (fout->remoteVersion >= 120000)
   12436         120 :             appendPQExpBufferStr(query,
   12437             :                                  "prosupport,\n");
   12438             :         else
   12439           0 :             appendPQExpBufferStr(query,
   12440             :                                  "'-' AS prosupport,\n");
   12441             : 
   12442         120 :         if (fout->remoteVersion >= 140000)
   12443         120 :             appendPQExpBufferStr(query,
   12444             :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   12445             :         else
   12446           0 :             appendPQExpBufferStr(query,
   12447             :                                  "NULL AS prosqlbody\n");
   12448             : 
   12449         120 :         appendPQExpBufferStr(query,
   12450             :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   12451             :                              "WHERE p.oid = $1 "
   12452             :                              "AND l.oid = p.prolang");
   12453             : 
   12454         120 :         ExecuteSqlStatement(fout, query->data);
   12455             : 
   12456         120 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   12457             :     }
   12458             : 
   12459        3454 :     printfPQExpBuffer(query,
   12460             :                       "EXECUTE dumpFunc('%u')",
   12461             :                       finfo->dobj.catId.oid);
   12462             : 
   12463        3454 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12464             : 
   12465        3454 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   12466        3454 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   12467             :     {
   12468        3356 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   12469        3356 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   12470        3356 :         prosqlbody = NULL;
   12471             :     }
   12472             :     else
   12473             :     {
   12474          98 :         prosrc = NULL;
   12475          98 :         probin = NULL;
   12476          98 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   12477             :     }
   12478        3454 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   12479        3454 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   12480        3454 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   12481        3454 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   12482        3454 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   12483        3454 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   12484        3454 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   12485        3454 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   12486        3454 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   12487        3454 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   12488        3454 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   12489        3454 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   12490        3454 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   12491        3454 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   12492        3454 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   12493             : 
   12494             :     /*
   12495             :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   12496             :      * is used.
   12497             :      */
   12498        3454 :     if (prosqlbody)
   12499             :     {
   12500          98 :         appendPQExpBufferStr(asPart, prosqlbody);
   12501             :     }
   12502        3356 :     else if (probin[0] != '\0')
   12503             :     {
   12504         286 :         appendPQExpBufferStr(asPart, "AS ");
   12505         286 :         appendStringLiteralAH(asPart, probin, fout);
   12506         286 :         if (prosrc[0] != '\0')
   12507             :         {
   12508         286 :             appendPQExpBufferStr(asPart, ", ");
   12509             : 
   12510             :             /*
   12511             :              * where we have bin, use dollar quoting if allowed and src
   12512             :              * contains quote or backslash; else use regular quoting.
   12513             :              */
   12514         286 :             if (dopt->disable_dollar_quoting ||
   12515         286 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   12516         286 :                 appendStringLiteralAH(asPart, prosrc, fout);
   12517             :             else
   12518           0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   12519             :         }
   12520             :     }
   12521             :     else
   12522             :     {
   12523        3070 :         appendPQExpBufferStr(asPart, "AS ");
   12524             :         /* with no bin, dollar quote src unconditionally if allowed */
   12525        3070 :         if (dopt->disable_dollar_quoting)
   12526           0 :             appendStringLiteralAH(asPart, prosrc, fout);
   12527             :         else
   12528        3070 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   12529             :     }
   12530             : 
   12531        3454 :     if (*proconfig)
   12532             :     {
   12533          30 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   12534           0 :             pg_fatal("could not parse %s array", "proconfig");
   12535             :     }
   12536             :     else
   12537             :     {
   12538        3424 :         configitems = NULL;
   12539        3424 :         nconfigitems = 0;
   12540             :     }
   12541             : 
   12542        3454 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   12543        3454 :     funcsig = format_function_arguments(finfo, funciargs, false);
   12544             : 
   12545        3454 :     funcsig_tag = format_function_signature(fout, finfo, false);
   12546             : 
   12547        3454 :     qual_funcsig = psprintf("%s.%s",
   12548        3454 :                             fmtId(finfo->dobj.namespace->dobj.name),
   12549             :                             funcsig);
   12550             : 
   12551        3454 :     if (prokind[0] == PROKIND_PROCEDURE)
   12552         156 :         keyword = "PROCEDURE";
   12553             :     else
   12554        3298 :         keyword = "FUNCTION"; /* works for window functions too */
   12555             : 
   12556        3454 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   12557             :                       keyword, qual_funcsig);
   12558             : 
   12559        6908 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   12560             :                       keyword,
   12561        3454 :                       fmtId(finfo->dobj.namespace->dobj.name),
   12562             :                       funcfullsig ? funcfullsig :
   12563             :                       funcsig);
   12564             : 
   12565        3454 :     if (prokind[0] == PROKIND_PROCEDURE)
   12566             :          /* no result type to output */ ;
   12567        3298 :     else if (funcresult)
   12568        3298 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   12569             :     else
   12570           0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   12571           0 :                           (proretset[0] == 't') ? "SETOF " : "",
   12572             :                           getFormattedTypeName(fout, finfo->prorettype,
   12573             :                                                zeroIsError));
   12574             : 
   12575        3454 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   12576             : 
   12577        3454 :     if (*protrftypes)
   12578             :     {
   12579           0 :         Oid        *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
   12580             :         int         i;
   12581             : 
   12582           0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   12583           0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   12584           0 :         for (i = 0; typeids[i]; i++)
   12585             :         {
   12586           0 :             if (i != 0)
   12587           0 :                 appendPQExpBufferStr(q, ", ");
   12588           0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   12589           0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   12590             :         }
   12591             :     }
   12592             : 
   12593        3454 :     if (prokind[0] == PROKIND_WINDOW)
   12594          10 :         appendPQExpBufferStr(q, " WINDOW");
   12595             : 
   12596        3454 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   12597             :     {
   12598         688 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   12599         656 :             appendPQExpBufferStr(q, " IMMUTABLE");
   12600          32 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   12601          32 :             appendPQExpBufferStr(q, " STABLE");
   12602           0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   12603           0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   12604             :                      finfo->dobj.name);
   12605             :     }
   12606             : 
   12607        3454 :     if (proisstrict[0] == 't')
   12608         694 :         appendPQExpBufferStr(q, " STRICT");
   12609             : 
   12610        3454 :     if (prosecdef[0] == 't')
   12611           0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   12612             : 
   12613        3454 :     if (proleakproof[0] == 't')
   12614          20 :         appendPQExpBufferStr(q, " LEAKPROOF");
   12615             : 
   12616             :     /*
   12617             :      * COST and ROWS are emitted only if present and not default, so as not to
   12618             :      * break backwards-compatibility of the dump without need.  Keep this code
   12619             :      * in sync with the defaults in functioncmds.c.
   12620             :      */
   12621        3454 :     if (strcmp(procost, "0") != 0)
   12622             :     {
   12623        3454 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   12624             :         {
   12625             :             /* default cost is 1 */
   12626         744 :             if (strcmp(procost, "1") != 0)
   12627           0 :                 appendPQExpBuffer(q, " COST %s", procost);
   12628             :         }
   12629             :         else
   12630             :         {
   12631             :             /* default cost is 100 */
   12632        2710 :             if (strcmp(procost, "100") != 0)
   12633          12 :                 appendPQExpBuffer(q, " COST %s", procost);
   12634             :         }
   12635             :     }
   12636        3454 :     if (proretset[0] == 't' &&
   12637         376 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   12638           0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   12639             : 
   12640        3454 :     if (strcmp(prosupport, "-") != 0)
   12641             :     {
   12642             :         /* We rely on regprocout to provide quoting and qualification */
   12643          86 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   12644             :     }
   12645             : 
   12646        3454 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   12647             :     {
   12648         228 :         if (proparallel[0] == PROPARALLEL_SAFE)
   12649         218 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   12650          10 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   12651          10 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   12652           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   12653           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   12654             :                      finfo->dobj.name);
   12655             :     }
   12656             : 
   12657        3524 :     for (int i = 0; i < nconfigitems; i++)
   12658             :     {
   12659             :         /* we feel free to scribble on configitems[] here */
   12660          70 :         char       *configitem = configitems[i];
   12661             :         char       *pos;
   12662             : 
   12663          70 :         pos = strchr(configitem, '=');
   12664          70 :         if (pos == NULL)
   12665           0 :             continue;
   12666          70 :         *pos++ = '\0';
   12667          70 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   12668             : 
   12669             :         /*
   12670             :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   12671             :          * by flatten_set_variable_args() before they were put into the
   12672             :          * proconfig array.  However, because the quoting rules used there
   12673             :          * aren't exactly like SQL's, we have to break the list value apart
   12674             :          * and then quote the elements as string literals.  (The elements may
   12675             :          * be double-quoted as-is, but we can't just feed them to the SQL
   12676             :          * parser; it would do the wrong thing with elements that are
   12677             :          * zero-length or longer than NAMEDATALEN.)
   12678             :          *
   12679             :          * Variables that are not so marked should just be emitted as simple
   12680             :          * string literals.  If the variable is not known to
   12681             :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   12682             :          * to use GUC_LIST_QUOTE for extension variables.
   12683             :          */
   12684          70 :         if (variable_is_guc_list_quote(configitem))
   12685             :         {
   12686             :             char      **namelist;
   12687             :             char      **nameptr;
   12688             : 
   12689             :             /* Parse string into list of identifiers */
   12690             :             /* this shouldn't fail really */
   12691          20 :             if (SplitGUCList(pos, ',', &namelist))
   12692             :             {
   12693          70 :                 for (nameptr = namelist; *nameptr; nameptr++)
   12694             :                 {
   12695          50 :                     if (nameptr != namelist)
   12696          30 :                         appendPQExpBufferStr(q, ", ");
   12697          50 :                     appendStringLiteralAH(q, *nameptr, fout);
   12698             :                 }
   12699             :             }
   12700          20 :             pg_free(namelist);
   12701             :         }
   12702             :         else
   12703          50 :             appendStringLiteralAH(q, pos, fout);
   12704             :     }
   12705             : 
   12706        3454 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   12707             : 
   12708        3454 :     append_depends_on_extension(fout, q, &finfo->dobj,
   12709             :                                 "pg_catalog.pg_proc", keyword,
   12710             :                                 qual_funcsig);
   12711             : 
   12712        3454 :     if (dopt->binary_upgrade)
   12713         564 :         binary_upgrade_extension_member(q, &finfo->dobj,
   12714             :                                         keyword, funcsig,
   12715         564 :                                         finfo->dobj.namespace->dobj.name);
   12716             : 
   12717        3454 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12718        3258 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   12719        3258 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   12720             :                                   .namespace = finfo->dobj.namespace->dobj.name,
   12721             :                                   .owner = finfo->rolname,
   12722             :                                   .description = keyword,
   12723             :                                   .section = finfo->postponed_def ?
   12724             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   12725             :                                   .createStmt = q->data,
   12726             :                                   .dropStmt = delqry->data));
   12727             : 
   12728             :     /* Dump Function Comments and Security Labels */
   12729        3454 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12730          10 :         dumpComment(fout, keyword, funcsig,
   12731          10 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   12732             :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   12733             : 
   12734        3454 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12735           0 :         dumpSecLabel(fout, keyword, funcsig,
   12736           0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   12737             :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   12738             : 
   12739        3454 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   12740         204 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   12741             :                 funcsig, NULL,
   12742         204 :                 finfo->dobj.namespace->dobj.name,
   12743             :                 NULL, finfo->rolname, &finfo->dacl);
   12744             : 
   12745        3454 :     PQclear(res);
   12746             : 
   12747        3454 :     destroyPQExpBuffer(query);
   12748        3454 :     destroyPQExpBuffer(q);
   12749        3454 :     destroyPQExpBuffer(delqry);
   12750        3454 :     destroyPQExpBuffer(asPart);
   12751        3454 :     free(funcsig);
   12752        3454 :     free(funcfullsig);
   12753        3454 :     free(funcsig_tag);
   12754        3454 :     free(qual_funcsig);
   12755        3454 :     free(configitems);
   12756             : }
   12757             : 
   12758             : 
   12759             : /*
   12760             :  * Dump a user-defined cast
   12761             :  */
   12762             : static void
   12763         130 : dumpCast(Archive *fout, const CastInfo *cast)
   12764             : {
   12765         130 :     DumpOptions *dopt = fout->dopt;
   12766             :     PQExpBuffer defqry;
   12767             :     PQExpBuffer delqry;
   12768             :     PQExpBuffer labelq;
   12769             :     PQExpBuffer castargs;
   12770         130 :     FuncInfo   *funcInfo = NULL;
   12771             :     const char *sourceType;
   12772             :     const char *targetType;
   12773             : 
   12774             :     /* Do nothing in data-only dump */
   12775         130 :     if (dopt->dataOnly)
   12776           6 :         return;
   12777             : 
   12778             :     /* Cannot dump if we don't have the cast function's info */
   12779         124 :     if (OidIsValid(cast->castfunc))
   12780             :     {
   12781          74 :         funcInfo = findFuncByOid(cast->castfunc);
   12782          74 :         if (funcInfo == NULL)
   12783           0 :             pg_fatal("could not find function definition for function with OID %u",
   12784             :                      cast->castfunc);
   12785             :     }
   12786             : 
   12787         124 :     defqry = createPQExpBuffer();
   12788         124 :     delqry = createPQExpBuffer();
   12789         124 :     labelq = createPQExpBuffer();
   12790         124 :     castargs = createPQExpBuffer();
   12791             : 
   12792         124 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   12793         124 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   12794         124 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   12795             :                       sourceType, targetType);
   12796             : 
   12797         124 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   12798             :                       sourceType, targetType);
   12799             : 
   12800         124 :     switch (cast->castmethod)
   12801             :     {
   12802          50 :         case COERCION_METHOD_BINARY:
   12803          50 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   12804          50 :             break;
   12805           0 :         case COERCION_METHOD_INOUT:
   12806           0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   12807           0 :             break;
   12808          74 :         case COERCION_METHOD_FUNCTION:
   12809          74 :             if (funcInfo)
   12810             :             {
   12811          74 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   12812             : 
   12813             :                 /*
   12814             :                  * Always qualify the function name (format_function_signature
   12815             :                  * won't qualify it).
   12816             :                  */
   12817          74 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   12818          74 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   12819          74 :                 free(fsig);
   12820             :             }
   12821             :             else
   12822           0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   12823          74 :             break;
   12824           0 :         default:
   12825           0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   12826             :     }
   12827             : 
   12828         124 :     if (cast->castcontext == 'a')
   12829          64 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   12830          60 :     else if (cast->castcontext == 'i')
   12831          20 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   12832         124 :     appendPQExpBufferStr(defqry, ";\n");
   12833             : 
   12834         124 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   12835             :                       sourceType, targetType);
   12836             : 
   12837         124 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   12838             :                       sourceType, targetType);
   12839             : 
   12840         124 :     if (dopt->binary_upgrade)
   12841          14 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   12842          14 :                                         "CAST", castargs->data, NULL);
   12843             : 
   12844         124 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12845         124 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   12846         124 :                      ARCHIVE_OPTS(.tag = labelq->data,
   12847             :                                   .description = "CAST",
   12848             :                                   .section = SECTION_PRE_DATA,
   12849             :                                   .createStmt = defqry->data,
   12850             :                                   .dropStmt = delqry->data));
   12851             : 
   12852             :     /* Dump Cast Comments */
   12853         124 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   12854           0 :         dumpComment(fout, "CAST", castargs->data,
   12855             :                     NULL, "",
   12856             :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   12857             : 
   12858         124 :     destroyPQExpBuffer(defqry);
   12859         124 :     destroyPQExpBuffer(delqry);
   12860         124 :     destroyPQExpBuffer(labelq);
   12861         124 :     destroyPQExpBuffer(castargs);
   12862             : }
   12863             : 
   12864             : /*
   12865             :  * Dump a transform
   12866             :  */
   12867             : static void
   12868          80 : dumpTransform(Archive *fout, const TransformInfo *transform)
   12869             : {
   12870          80 :     DumpOptions *dopt = fout->dopt;
   12871             :     PQExpBuffer defqry;
   12872             :     PQExpBuffer delqry;
   12873             :     PQExpBuffer labelq;
   12874             :     PQExpBuffer transformargs;
   12875          80 :     FuncInfo   *fromsqlFuncInfo = NULL;
   12876          80 :     FuncInfo   *tosqlFuncInfo = NULL;
   12877             :     char       *lanname;
   12878             :     const char *transformType;
   12879             : 
   12880             :     /* Do nothing in data-only dump */
   12881          80 :     if (dopt->dataOnly)
   12882           6 :         return;
   12883             : 
   12884             :     /* Cannot dump if we don't have the transform functions' info */
   12885          74 :     if (OidIsValid(transform->trffromsql))
   12886             :     {
   12887          74 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   12888          74 :         if (fromsqlFuncInfo == NULL)
   12889           0 :             pg_fatal("could not find function definition for function with OID %u",
   12890             :                      transform->trffromsql);
   12891             :     }
   12892          74 :     if (OidIsValid(transform->trftosql))
   12893             :     {
   12894          74 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   12895          74 :         if (tosqlFuncInfo == NULL)
   12896           0 :             pg_fatal("could not find function definition for function with OID %u",
   12897             :                      transform->trftosql);
   12898             :     }
   12899             : 
   12900          74 :     defqry = createPQExpBuffer();
   12901          74 :     delqry = createPQExpBuffer();
   12902          74 :     labelq = createPQExpBuffer();
   12903          74 :     transformargs = createPQExpBuffer();
   12904             : 
   12905          74 :     lanname = get_language_name(fout, transform->trflang);
   12906          74 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   12907             : 
   12908          74 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   12909             :                       transformType, lanname);
   12910             : 
   12911          74 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   12912             :                       transformType, lanname);
   12913             : 
   12914          74 :     if (!transform->trffromsql && !transform->trftosql)
   12915           0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   12916             : 
   12917          74 :     if (transform->trffromsql)
   12918             :     {
   12919          74 :         if (fromsqlFuncInfo)
   12920             :         {
   12921          74 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   12922             : 
   12923             :             /*
   12924             :              * Always qualify the function name (format_function_signature
   12925             :              * won't qualify it).
   12926             :              */
   12927          74 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   12928          74 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   12929          74 :             free(fsig);
   12930             :         }
   12931             :         else
   12932           0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   12933             :     }
   12934             : 
   12935          74 :     if (transform->trftosql)
   12936             :     {
   12937          74 :         if (transform->trffromsql)
   12938          74 :             appendPQExpBufferStr(defqry, ", ");
   12939             : 
   12940          74 :         if (tosqlFuncInfo)
   12941             :         {
   12942          74 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   12943             : 
   12944             :             /*
   12945             :              * Always qualify the function name (format_function_signature
   12946             :              * won't qualify it).
   12947             :              */
   12948          74 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   12949          74 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   12950          74 :             free(fsig);
   12951             :         }
   12952             :         else
   12953           0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   12954             :     }
   12955             : 
   12956          74 :     appendPQExpBufferStr(defqry, ");\n");
   12957             : 
   12958          74 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   12959             :                       transformType, lanname);
   12960             : 
   12961          74 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   12962             :                       transformType, lanname);
   12963             : 
   12964          74 :     if (dopt->binary_upgrade)
   12965           4 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   12966           4 :                                         "TRANSFORM", transformargs->data, NULL);
   12967             : 
   12968          74 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12969          74 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   12970          74 :                      ARCHIVE_OPTS(.tag = labelq->data,
   12971             :                                   .description = "TRANSFORM",
   12972             :                                   .section = SECTION_PRE_DATA,
   12973             :                                   .createStmt = defqry->data,
   12974             :                                   .dropStmt = delqry->data,
   12975             :                                   .deps = transform->dobj.dependencies,
   12976             :                                   .nDeps = transform->dobj.nDeps));
   12977             : 
   12978             :     /* Dump Transform Comments */
   12979          74 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   12980           0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   12981             :                     NULL, "",
   12982             :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   12983             : 
   12984          74 :     free(lanname);
   12985          74 :     destroyPQExpBuffer(defqry);
   12986          74 :     destroyPQExpBuffer(delqry);
   12987          74 :     destroyPQExpBuffer(labelq);
   12988          74 :     destroyPQExpBuffer(transformargs);
   12989             : }
   12990             : 
   12991             : 
   12992             : /*
   12993             :  * dumpOpr
   12994             :  *    write out a single operator definition
   12995             :  */
   12996             : static void
   12997        1808 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   12998             : {
   12999        1808 :     DumpOptions *dopt = fout->dopt;
   13000             :     PQExpBuffer query;
   13001             :     PQExpBuffer q;
   13002             :     PQExpBuffer delq;
   13003             :     PQExpBuffer oprid;
   13004             :     PQExpBuffer details;
   13005             :     PGresult   *res;
   13006             :     int         i_oprkind;
   13007             :     int         i_oprcode;
   13008             :     int         i_oprleft;
   13009             :     int         i_oprright;
   13010             :     int         i_oprcom;
   13011             :     int         i_oprnegate;
   13012             :     int         i_oprrest;
   13013             :     int         i_oprjoin;
   13014             :     int         i_oprcanmerge;
   13015             :     int         i_oprcanhash;
   13016             :     char       *oprkind;
   13017             :     char       *oprcode;
   13018             :     char       *oprleft;
   13019             :     char       *oprright;
   13020             :     char       *oprcom;
   13021             :     char       *oprnegate;
   13022             :     char       *oprrest;
   13023             :     char       *oprjoin;
   13024             :     char       *oprcanmerge;
   13025             :     char       *oprcanhash;
   13026             :     char       *oprregproc;
   13027             :     char       *oprref;
   13028             : 
   13029             :     /* Do nothing in data-only dump */
   13030        1808 :     if (dopt->dataOnly)
   13031           6 :         return;
   13032             : 
   13033             :     /*
   13034             :      * some operators are invalid because they were the result of user
   13035             :      * defining operators before commutators exist
   13036             :      */
   13037        1802 :     if (!OidIsValid(oprinfo->oprcode))
   13038          28 :         return;
   13039             : 
   13040        1774 :     query = createPQExpBuffer();
   13041        1774 :     q = createPQExpBuffer();
   13042        1774 :     delq = createPQExpBuffer();
   13043        1774 :     oprid = createPQExpBuffer();
   13044        1774 :     details = createPQExpBuffer();
   13045             : 
   13046        1774 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   13047             :     {
   13048             :         /* Set up query for operator-specific details */
   13049          78 :         appendPQExpBufferStr(query,
   13050             :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   13051             :                              "SELECT oprkind, "
   13052             :                              "oprcode::pg_catalog.regprocedure, "
   13053             :                              "oprleft::pg_catalog.regtype, "
   13054             :                              "oprright::pg_catalog.regtype, "
   13055             :                              "oprcom, "
   13056             :                              "oprnegate, "
   13057             :                              "oprrest::pg_catalog.regprocedure, "
   13058             :                              "oprjoin::pg_catalog.regprocedure, "
   13059             :                              "oprcanmerge, oprcanhash "
   13060             :                              "FROM pg_catalog.pg_operator "
   13061             :                              "WHERE oid = $1");
   13062             : 
   13063          78 :         ExecuteSqlStatement(fout, query->data);
   13064             : 
   13065          78 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   13066             :     }
   13067             : 
   13068        1774 :     printfPQExpBuffer(query,
   13069             :                       "EXECUTE dumpOpr('%u')",
   13070             :                       oprinfo->dobj.catId.oid);
   13071             : 
   13072        1774 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13073             : 
   13074        1774 :     i_oprkind = PQfnumber(res, "oprkind");
   13075        1774 :     i_oprcode = PQfnumber(res, "oprcode");
   13076        1774 :     i_oprleft = PQfnumber(res, "oprleft");
   13077        1774 :     i_oprright = PQfnumber(res, "oprright");
   13078        1774 :     i_oprcom = PQfnumber(res, "oprcom");
   13079        1774 :     i_oprnegate = PQfnumber(res, "oprnegate");
   13080        1774 :     i_oprrest = PQfnumber(res, "oprrest");
   13081        1774 :     i_oprjoin = PQfnumber(res, "oprjoin");
   13082        1774 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   13083        1774 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   13084             : 
   13085        1774 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   13086        1774 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   13087        1774 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   13088        1774 :     oprright = PQgetvalue(res, 0, i_oprright);
   13089        1774 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   13090        1774 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   13091        1774 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   13092        1774 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   13093        1774 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   13094        1774 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   13095             : 
   13096             :     /* In PG14 upwards postfix operator support does not exist anymore. */
   13097        1774 :     if (strcmp(oprkind, "r") == 0)
   13098           0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   13099             :                        oprcode);
   13100             : 
   13101        1774 :     oprregproc = convertRegProcReference(oprcode);
   13102        1774 :     if (oprregproc)
   13103             :     {
   13104        1774 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   13105        1774 :         free(oprregproc);
   13106             :     }
   13107             : 
   13108        1774 :     appendPQExpBuffer(oprid, "%s (",
   13109             :                       oprinfo->dobj.name);
   13110             : 
   13111             :     /*
   13112             :      * right unary means there's a left arg and left unary means there's a
   13113             :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   13114             :      * continue to support it in case we're dumping from an old server.)
   13115             :      */
   13116        1774 :     if (strcmp(oprkind, "r") == 0 ||
   13117        1774 :         strcmp(oprkind, "b") == 0)
   13118             :     {
   13119        1652 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   13120        1652 :         appendPQExpBufferStr(oprid, oprleft);
   13121             :     }
   13122             :     else
   13123         122 :         appendPQExpBufferStr(oprid, "NONE");
   13124             : 
   13125        1774 :     if (strcmp(oprkind, "l") == 0 ||
   13126        1652 :         strcmp(oprkind, "b") == 0)
   13127             :     {
   13128        1774 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   13129        1774 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   13130             :     }
   13131             :     else
   13132           0 :         appendPQExpBufferStr(oprid, ", NONE)");
   13133             : 
   13134        1774 :     oprref = getFormattedOperatorName(oprcom);
   13135        1774 :     if (oprref)
   13136             :     {
   13137        1134 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   13138        1134 :         free(oprref);
   13139             :     }
   13140             : 
   13141        1774 :     oprref = getFormattedOperatorName(oprnegate);
   13142        1774 :     if (oprref)
   13143             :     {
   13144         782 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   13145         782 :         free(oprref);
   13146             :     }
   13147             : 
   13148        1774 :     if (strcmp(oprcanmerge, "t") == 0)
   13149         150 :         appendPQExpBufferStr(details, ",\n    MERGES");
   13150             : 
   13151        1774 :     if (strcmp(oprcanhash, "t") == 0)
   13152          92 :         appendPQExpBufferStr(details, ",\n    HASHES");
   13153             : 
   13154        1774 :     oprregproc = convertRegProcReference(oprrest);
   13155        1774 :     if (oprregproc)
   13156             :     {
   13157        1036 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   13158        1036 :         free(oprregproc);
   13159             :     }
   13160             : 
   13161        1774 :     oprregproc = convertRegProcReference(oprjoin);
   13162        1774 :     if (oprregproc)
   13163             :     {
   13164        1036 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   13165        1036 :         free(oprregproc);
   13166             :     }
   13167             : 
   13168        1774 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   13169        1774 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13170             :                       oprid->data);
   13171             : 
   13172        1774 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   13173        1774 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13174             :                       oprinfo->dobj.name, details->data);
   13175             : 
   13176        1774 :     if (dopt->binary_upgrade)
   13177          24 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   13178          24 :                                         "OPERATOR", oprid->data,
   13179          24 :                                         oprinfo->dobj.namespace->dobj.name);
   13180             : 
   13181        1774 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13182        1774 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   13183        1774 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   13184             :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   13185             :                                   .owner = oprinfo->rolname,
   13186             :                                   .description = "OPERATOR",
   13187             :                                   .section = SECTION_PRE_DATA,
   13188             :                                   .createStmt = q->data,
   13189             :                                   .dropStmt = delq->data));
   13190             : 
   13191             :     /* Dump Operator Comments */
   13192        1774 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13193        1598 :         dumpComment(fout, "OPERATOR", oprid->data,
   13194        1598 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   13195             :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   13196             : 
   13197        1774 :     PQclear(res);
   13198             : 
   13199        1774 :     destroyPQExpBuffer(query);
   13200        1774 :     destroyPQExpBuffer(q);
   13201        1774 :     destroyPQExpBuffer(delq);
   13202        1774 :     destroyPQExpBuffer(oprid);
   13203        1774 :     destroyPQExpBuffer(details);
   13204             : }
   13205             : 
   13206             : /*
   13207             :  * Convert a function reference obtained from pg_operator
   13208             :  *
   13209             :  * Returns allocated string of what to print, or NULL if function references
   13210             :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   13211             :  *
   13212             :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   13213             :  * part.
   13214             :  */
   13215             : static char *
   13216        5322 : convertRegProcReference(const char *proc)
   13217             : {
   13218             :     char       *name;
   13219             :     char       *paren;
   13220             :     bool        inquote;
   13221             : 
   13222             :     /* In all cases "-" means a null reference */
   13223        5322 :     if (strcmp(proc, "-") == 0)
   13224        1476 :         return NULL;
   13225             : 
   13226        3846 :     name = pg_strdup(proc);
   13227             :     /* find non-double-quoted left paren */
   13228        3846 :     inquote = false;
   13229       46214 :     for (paren = name; *paren; paren++)
   13230             :     {
   13231       46214 :         if (*paren == '(' && !inquote)
   13232             :         {
   13233        3846 :             *paren = '\0';
   13234        3846 :             break;
   13235             :         }
   13236       42368 :         if (*paren == '"')
   13237         100 :             inquote = !inquote;
   13238             :     }
   13239        3846 :     return name;
   13240             : }
   13241             : 
   13242             : /*
   13243             :  * getFormattedOperatorName - retrieve the operator name for the
   13244             :  * given operator OID (presented in string form).
   13245             :  *
   13246             :  * Returns an allocated string, or NULL if the given OID is invalid.
   13247             :  * Caller is responsible for free'ing result string.
   13248             :  *
   13249             :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   13250             :  * useful in commands where the operator's argument types can be inferred from
   13251             :  * context.  We always schema-qualify the name, though.  The predecessor to
   13252             :  * this code tried to skip the schema qualification if possible, but that led
   13253             :  * to wrong results in corner cases, such as if an operator and its negator
   13254             :  * are in different schemas.
   13255             :  */
   13256             : static char *
   13257        4120 : getFormattedOperatorName(const char *oproid)
   13258             : {
   13259             :     OprInfo    *oprInfo;
   13260             : 
   13261             :     /* In all cases "0" means a null reference */
   13262        4120 :     if (strcmp(oproid, "0") == 0)
   13263        2204 :         return NULL;
   13264             : 
   13265        1916 :     oprInfo = findOprByOid(atooid(oproid));
   13266        1916 :     if (oprInfo == NULL)
   13267             :     {
   13268           0 :         pg_log_warning("could not find operator with OID %s",
   13269             :                        oproid);
   13270           0 :         return NULL;
   13271             :     }
   13272             : 
   13273        1916 :     return psprintf("OPERATOR(%s.%s)",
   13274        1916 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   13275             :                     oprInfo->dobj.name);
   13276             : }
   13277             : 
   13278             : /*
   13279             :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   13280             :  *
   13281             :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   13282             :  * argument lists of these functions are predetermined.  Note that the
   13283             :  * caller should ensure we are in the proper schema, because the results
   13284             :  * are search path dependent!
   13285             :  */
   13286             : static char *
   13287         360 : convertTSFunction(Archive *fout, Oid funcOid)
   13288             : {
   13289             :     char       *result;
   13290             :     char        query[128];
   13291             :     PGresult   *res;
   13292             : 
   13293         360 :     snprintf(query, sizeof(query),
   13294             :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   13295         360 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   13296             : 
   13297         360 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   13298             : 
   13299         360 :     PQclear(res);
   13300             : 
   13301         360 :     return result;
   13302             : }
   13303             : 
   13304             : /*
   13305             :  * dumpAccessMethod
   13306             :  *    write out a single access method definition
   13307             :  */
   13308             : static void
   13309         152 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   13310             : {
   13311         152 :     DumpOptions *dopt = fout->dopt;
   13312             :     PQExpBuffer q;
   13313             :     PQExpBuffer delq;
   13314             :     char       *qamname;
   13315             : 
   13316             :     /* Do nothing in data-only dump */
   13317         152 :     if (dopt->dataOnly)
   13318          12 :         return;
   13319             : 
   13320         140 :     q = createPQExpBuffer();
   13321         140 :     delq = createPQExpBuffer();
   13322             : 
   13323         140 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   13324             : 
   13325         140 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   13326             : 
   13327         140 :     switch (aminfo->amtype)
   13328             :     {
   13329          66 :         case AMTYPE_INDEX:
   13330          66 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   13331          66 :             break;
   13332          74 :         case AMTYPE_TABLE:
   13333          74 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   13334          74 :             break;
   13335           0 :         default:
   13336           0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   13337             :                            aminfo->amtype, qamname);
   13338           0 :             destroyPQExpBuffer(q);
   13339           0 :             destroyPQExpBuffer(delq);
   13340           0 :             free(qamname);
   13341           0 :             return;
   13342             :     }
   13343             : 
   13344         140 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   13345             : 
   13346         140 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   13347             :                       qamname);
   13348             : 
   13349         140 :     if (dopt->binary_upgrade)
   13350           8 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   13351             :                                         "ACCESS METHOD", qamname, NULL);
   13352             : 
   13353         140 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13354         140 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   13355         140 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   13356             :                                   .description = "ACCESS METHOD",
   13357             :                                   .section = SECTION_PRE_DATA,
   13358             :                                   .createStmt = q->data,
   13359             :                                   .dropStmt = delq->data));
   13360             : 
   13361             :     /* Dump Access Method Comments */
   13362         140 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13363           0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   13364             :                     NULL, "",
   13365             :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   13366             : 
   13367         140 :     destroyPQExpBuffer(q);
   13368         140 :     destroyPQExpBuffer(delq);
   13369         140 :     free(qamname);
   13370             : }
   13371             : 
   13372             : /*
   13373             :  * dumpOpclass
   13374             :  *    write out a single operator class definition
   13375             :  */
   13376             : static void
   13377         600 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   13378             : {
   13379         600 :     DumpOptions *dopt = fout->dopt;
   13380             :     PQExpBuffer query;
   13381             :     PQExpBuffer q;
   13382             :     PQExpBuffer delq;
   13383             :     PQExpBuffer nameusing;
   13384             :     PGresult   *res;
   13385             :     int         ntups;
   13386             :     int         i_opcintype;
   13387             :     int         i_opckeytype;
   13388             :     int         i_opcdefault;
   13389             :     int         i_opcfamily;
   13390             :     int         i_opcfamilyname;
   13391             :     int         i_opcfamilynsp;
   13392             :     int         i_amname;
   13393             :     int         i_amopstrategy;
   13394             :     int         i_amopopr;
   13395             :     int         i_sortfamily;
   13396             :     int         i_sortfamilynsp;
   13397             :     int         i_amprocnum;
   13398             :     int         i_amproc;
   13399             :     int         i_amproclefttype;
   13400             :     int         i_amprocrighttype;
   13401             :     char       *opcintype;
   13402             :     char       *opckeytype;
   13403             :     char       *opcdefault;
   13404             :     char       *opcfamily;
   13405             :     char       *opcfamilyname;
   13406             :     char       *opcfamilynsp;
   13407             :     char       *amname;
   13408             :     char       *amopstrategy;
   13409             :     char       *amopopr;
   13410             :     char       *sortfamily;
   13411             :     char       *sortfamilynsp;
   13412             :     char       *amprocnum;
   13413             :     char       *amproc;
   13414             :     char       *amproclefttype;
   13415             :     char       *amprocrighttype;
   13416             :     bool        needComma;
   13417             :     int         i;
   13418             : 
   13419             :     /* Do nothing in data-only dump */
   13420         600 :     if (dopt->dataOnly)
   13421          18 :         return;
   13422             : 
   13423         582 :     query = createPQExpBuffer();
   13424         582 :     q = createPQExpBuffer();
   13425         582 :     delq = createPQExpBuffer();
   13426         582 :     nameusing = createPQExpBuffer();
   13427             : 
   13428             :     /* Get additional fields from the pg_opclass row */
   13429         582 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   13430             :                       "opckeytype::pg_catalog.regtype, "
   13431             :                       "opcdefault, opcfamily, "
   13432             :                       "opfname AS opcfamilyname, "
   13433             :                       "nspname AS opcfamilynsp, "
   13434             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   13435             :                       "FROM pg_catalog.pg_opclass c "
   13436             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   13437             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13438             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   13439             :                       opcinfo->dobj.catId.oid);
   13440             : 
   13441         582 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13442             : 
   13443         582 :     i_opcintype = PQfnumber(res, "opcintype");
   13444         582 :     i_opckeytype = PQfnumber(res, "opckeytype");
   13445         582 :     i_opcdefault = PQfnumber(res, "opcdefault");
   13446         582 :     i_opcfamily = PQfnumber(res, "opcfamily");
   13447         582 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   13448         582 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   13449         582 :     i_amname = PQfnumber(res, "amname");
   13450             : 
   13451             :     /* opcintype may still be needed after we PQclear res */
   13452         582 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   13453         582 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   13454         582 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   13455             :     /* opcfamily will still be needed after we PQclear res */
   13456         582 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   13457         582 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   13458         582 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   13459             :     /* amname will still be needed after we PQclear res */
   13460         582 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   13461             : 
   13462         582 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   13463         582 :                       fmtQualifiedDumpable(opcinfo));
   13464         582 :     appendPQExpBuffer(delq, " USING %s;\n",
   13465             :                       fmtId(amname));
   13466             : 
   13467             :     /* Build the fixed portion of the CREATE command */
   13468         582 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   13469         582 :                       fmtQualifiedDumpable(opcinfo));
   13470         582 :     if (strcmp(opcdefault, "t") == 0)
   13471         238 :         appendPQExpBufferStr(q, "DEFAULT ");
   13472         582 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   13473             :                       opcintype,
   13474             :                       fmtId(amname));
   13475         582 :     if (strlen(opcfamilyname) > 0)
   13476             :     {
   13477         582 :         appendPQExpBufferStr(q, " FAMILY ");
   13478         582 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   13479         582 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   13480             :     }
   13481         582 :     appendPQExpBufferStr(q, " AS\n    ");
   13482             : 
   13483         582 :     needComma = false;
   13484             : 
   13485         582 :     if (strcmp(opckeytype, "-") != 0)
   13486             :     {
   13487         168 :         appendPQExpBuffer(q, "STORAGE %s",
   13488             :                           opckeytype);
   13489         168 :         needComma = true;
   13490             :     }
   13491             : 
   13492         582 :     PQclear(res);
   13493             : 
   13494             :     /*
   13495             :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   13496             :      *
   13497             :      * Print only those opfamily members that are tied to the opclass by
   13498             :      * pg_depend entries.
   13499             :      */
   13500         582 :     resetPQExpBuffer(query);
   13501         582 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   13502             :                       "amopopr::pg_catalog.regoperator, "
   13503             :                       "opfname AS sortfamily, "
   13504             :                       "nspname AS sortfamilynsp "
   13505             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   13506             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   13507             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   13508             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13509             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   13510             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13511             :                       "AND amopfamily = '%s'::pg_catalog.oid "
   13512             :                       "ORDER BY amopstrategy",
   13513             :                       opcinfo->dobj.catId.oid,
   13514             :                       opcfamily);
   13515             : 
   13516         582 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13517             : 
   13518         582 :     ntups = PQntuples(res);
   13519             : 
   13520         582 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   13521         582 :     i_amopopr = PQfnumber(res, "amopopr");
   13522         582 :     i_sortfamily = PQfnumber(res, "sortfamily");
   13523         582 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   13524             : 
   13525         998 :     for (i = 0; i < ntups; i++)
   13526             :     {
   13527         416 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   13528         416 :         amopopr = PQgetvalue(res, i, i_amopopr);
   13529         416 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   13530         416 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   13531             : 
   13532         416 :         if (needComma)
   13533         264 :             appendPQExpBufferStr(q, " ,\n    ");
   13534             : 
   13535         416 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   13536             :                           amopstrategy, amopopr);
   13537             : 
   13538         416 :         if (strlen(sortfamily) > 0)
   13539             :         {
   13540           0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   13541           0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   13542           0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   13543             :         }
   13544             : 
   13545         416 :         needComma = true;
   13546             :     }
   13547             : 
   13548         582 :     PQclear(res);
   13549             : 
   13550             :     /*
   13551             :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   13552             :      *
   13553             :      * Print only those opfamily members that are tied to the opclass by
   13554             :      * pg_depend entries.
   13555             :      *
   13556             :      * We print the amproclefttype/amprocrighttype even though in most cases
   13557             :      * the backend could deduce the right values, because of the corner case
   13558             :      * of a btree sort support function for a cross-type comparison.
   13559             :      */
   13560         582 :     resetPQExpBuffer(query);
   13561             : 
   13562         582 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   13563             :                       "amproc::pg_catalog.regprocedure, "
   13564             :                       "amproclefttype::pg_catalog.regtype, "
   13565             :                       "amprocrighttype::pg_catalog.regtype "
   13566             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   13567             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   13568             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13569             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   13570             :                       "AND objid = ap.oid "
   13571             :                       "ORDER BY amprocnum",
   13572             :                       opcinfo->dobj.catId.oid);
   13573             : 
   13574         582 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13575             : 
   13576         582 :     ntups = PQntuples(res);
   13577             : 
   13578         582 :     i_amprocnum = PQfnumber(res, "amprocnum");
   13579         582 :     i_amproc = PQfnumber(res, "amproc");
   13580         582 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   13581         582 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   13582             : 
   13583         648 :     for (i = 0; i < ntups; i++)
   13584             :     {
   13585          66 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   13586          66 :         amproc = PQgetvalue(res, i, i_amproc);
   13587          66 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   13588          66 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   13589             : 
   13590          66 :         if (needComma)
   13591          66 :             appendPQExpBufferStr(q, " ,\n    ");
   13592             : 
   13593          66 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   13594             : 
   13595          66 :         if (*amproclefttype && *amprocrighttype)
   13596          66 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   13597             : 
   13598          66 :         appendPQExpBuffer(q, " %s", amproc);
   13599             : 
   13600          66 :         needComma = true;
   13601             :     }
   13602             : 
   13603         582 :     PQclear(res);
   13604             : 
   13605             :     /*
   13606             :      * If needComma is still false it means we haven't added anything after
   13607             :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   13608             :      * clause with the same datatype.  This isn't sanctioned by the
   13609             :      * documentation, but actually DefineOpClass will treat it as a no-op.
   13610             :      */
   13611         582 :     if (!needComma)
   13612         262 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   13613             : 
   13614         582 :     appendPQExpBufferStr(q, ";\n");
   13615             : 
   13616         582 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   13617         582 :     appendPQExpBuffer(nameusing, " USING %s",
   13618             :                       fmtId(amname));
   13619             : 
   13620         582 :     if (dopt->binary_upgrade)
   13621          12 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   13622          12 :                                         "OPERATOR CLASS", nameusing->data,
   13623          12 :                                         opcinfo->dobj.namespace->dobj.name);
   13624             : 
   13625         582 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13626         582 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   13627         582 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   13628             :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   13629             :                                   .owner = opcinfo->rolname,
   13630             :                                   .description = "OPERATOR CLASS",
   13631             :                                   .section = SECTION_PRE_DATA,
   13632             :                                   .createStmt = q->data,
   13633             :                                   .dropStmt = delq->data));
   13634             : 
   13635             :     /* Dump Operator Class Comments */
   13636         582 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13637           0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   13638           0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   13639             :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   13640             : 
   13641         582 :     free(opcintype);
   13642         582 :     free(opcfamily);
   13643         582 :     free(amname);
   13644         582 :     destroyPQExpBuffer(query);
   13645         582 :     destroyPQExpBuffer(q);
   13646         582 :     destroyPQExpBuffer(delq);
   13647         582 :     destroyPQExpBuffer(nameusing);
   13648             : }
   13649             : 
   13650             : /*
   13651             :  * dumpOpfamily
   13652             :  *    write out a single operator family definition
   13653             :  *
   13654             :  * Note: this also dumps any "loose" operator members that aren't bound to a
   13655             :  * specific opclass within the opfamily.
   13656             :  */
   13657             : static void
   13658         506 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   13659             : {
   13660         506 :     DumpOptions *dopt = fout->dopt;
   13661             :     PQExpBuffer query;
   13662             :     PQExpBuffer q;
   13663             :     PQExpBuffer delq;
   13664             :     PQExpBuffer nameusing;
   13665             :     PGresult   *res;
   13666             :     PGresult   *res_ops;
   13667             :     PGresult   *res_procs;
   13668             :     int         ntups;
   13669             :     int         i_amname;
   13670             :     int         i_amopstrategy;
   13671             :     int         i_amopopr;
   13672             :     int         i_sortfamily;
   13673             :     int         i_sortfamilynsp;
   13674             :     int         i_amprocnum;
   13675             :     int         i_amproc;
   13676             :     int         i_amproclefttype;
   13677             :     int         i_amprocrighttype;
   13678             :     char       *amname;
   13679             :     char       *amopstrategy;
   13680             :     char       *amopopr;
   13681             :     char       *sortfamily;
   13682             :     char       *sortfamilynsp;
   13683             :     char       *amprocnum;
   13684             :     char       *amproc;
   13685             :     char       *amproclefttype;
   13686             :     char       *amprocrighttype;
   13687             :     bool        needComma;
   13688             :     int         i;
   13689             : 
   13690             :     /* Do nothing in data-only dump */
   13691         506 :     if (dopt->dataOnly)
   13692          12 :         return;
   13693             : 
   13694         494 :     query = createPQExpBuffer();
   13695         494 :     q = createPQExpBuffer();
   13696         494 :     delq = createPQExpBuffer();
   13697         494 :     nameusing = createPQExpBuffer();
   13698             : 
   13699             :     /*
   13700             :      * Fetch only those opfamily members that are tied directly to the
   13701             :      * opfamily by pg_depend entries.
   13702             :      */
   13703         494 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   13704             :                       "amopopr::pg_catalog.regoperator, "
   13705             :                       "opfname AS sortfamily, "
   13706             :                       "nspname AS sortfamilynsp "
   13707             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   13708             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   13709             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   13710             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13711             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   13712             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13713             :                       "AND amopfamily = '%u'::pg_catalog.oid "
   13714             :                       "ORDER BY amopstrategy",
   13715             :                       opfinfo->dobj.catId.oid,
   13716             :                       opfinfo->dobj.catId.oid);
   13717             : 
   13718         494 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13719             : 
   13720         494 :     resetPQExpBuffer(query);
   13721             : 
   13722         494 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   13723             :                       "amproc::pg_catalog.regprocedure, "
   13724             :                       "amproclefttype::pg_catalog.regtype, "
   13725             :                       "amprocrighttype::pg_catalog.regtype "
   13726             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   13727             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   13728             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13729             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   13730             :                       "AND objid = ap.oid "
   13731             :                       "ORDER BY amprocnum",
   13732             :                       opfinfo->dobj.catId.oid);
   13733             : 
   13734         494 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13735             : 
   13736             :     /* Get additional fields from the pg_opfamily row */
   13737         494 :     resetPQExpBuffer(query);
   13738             : 
   13739         494 :     appendPQExpBuffer(query, "SELECT "
   13740             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   13741             :                       "FROM pg_catalog.pg_opfamily "
   13742             :                       "WHERE oid = '%u'::pg_catalog.oid",
   13743             :                       opfinfo->dobj.catId.oid);
   13744             : 
   13745         494 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13746             : 
   13747         494 :     i_amname = PQfnumber(res, "amname");
   13748             : 
   13749             :     /* amname will still be needed after we PQclear res */
   13750         494 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   13751             : 
   13752         494 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   13753         494 :                       fmtQualifiedDumpable(opfinfo));
   13754         494 :     appendPQExpBuffer(delq, " USING %s;\n",
   13755             :                       fmtId(amname));
   13756             : 
   13757             :     /* Build the fixed portion of the CREATE command */
   13758         494 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   13759         494 :                       fmtQualifiedDumpable(opfinfo));
   13760         494 :     appendPQExpBuffer(q, " USING %s;\n",
   13761             :                       fmtId(amname));
   13762             : 
   13763         494 :     PQclear(res);
   13764             : 
   13765             :     /* Do we need an ALTER to add loose members? */
   13766         494 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   13767             :     {
   13768          96 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   13769          96 :                           fmtQualifiedDumpable(opfinfo));
   13770          96 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   13771             :                           fmtId(amname));
   13772             : 
   13773          96 :         needComma = false;
   13774             : 
   13775             :         /*
   13776             :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   13777             :          */
   13778          96 :         ntups = PQntuples(res_ops);
   13779             : 
   13780          96 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   13781          96 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   13782          96 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   13783          96 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   13784             : 
   13785         426 :         for (i = 0; i < ntups; i++)
   13786             :         {
   13787         330 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   13788         330 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   13789         330 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   13790         330 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   13791             : 
   13792         330 :             if (needComma)
   13793         264 :                 appendPQExpBufferStr(q, " ,\n    ");
   13794             : 
   13795         330 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   13796             :                               amopstrategy, amopopr);
   13797             : 
   13798         330 :             if (strlen(sortfamily) > 0)
   13799             :             {
   13800           0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   13801           0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   13802           0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   13803             :             }
   13804             : 
   13805         330 :             needComma = true;
   13806             :         }
   13807             : 
   13808             :         /*
   13809             :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   13810             :          */
   13811          96 :         ntups = PQntuples(res_procs);
   13812             : 
   13813          96 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   13814          96 :         i_amproc = PQfnumber(res_procs, "amproc");
   13815          96 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   13816          96 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   13817             : 
   13818         456 :         for (i = 0; i < ntups; i++)
   13819             :         {
   13820         360 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   13821         360 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   13822         360 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   13823         360 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   13824             : 
   13825         360 :             if (needComma)
   13826         330 :                 appendPQExpBufferStr(q, " ,\n    ");
   13827             : 
   13828         360 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   13829             :                               amprocnum, amproclefttype, amprocrighttype,
   13830             :                               amproc);
   13831             : 
   13832         360 :             needComma = true;
   13833             :         }
   13834             : 
   13835          96 :         appendPQExpBufferStr(q, ";\n");
   13836             :     }
   13837             : 
   13838         494 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   13839         494 :     appendPQExpBuffer(nameusing, " USING %s",
   13840             :                       fmtId(amname));
   13841             : 
   13842         494 :     if (dopt->binary_upgrade)
   13843          18 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   13844          18 :                                         "OPERATOR FAMILY", nameusing->data,
   13845          18 :                                         opfinfo->dobj.namespace->dobj.name);
   13846             : 
   13847         494 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13848         494 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   13849         494 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   13850             :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   13851             :                                   .owner = opfinfo->rolname,
   13852             :                                   .description = "OPERATOR FAMILY",
   13853             :                                   .section = SECTION_PRE_DATA,
   13854             :                                   .createStmt = q->data,
   13855             :                                   .dropStmt = delq->data));
   13856             : 
   13857             :     /* Dump Operator Family Comments */
   13858         494 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13859           0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   13860           0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   13861             :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   13862             : 
   13863         494 :     free(amname);
   13864         494 :     PQclear(res_ops);
   13865         494 :     PQclear(res_procs);
   13866         494 :     destroyPQExpBuffer(query);
   13867         494 :     destroyPQExpBuffer(q);
   13868         494 :     destroyPQExpBuffer(delq);
   13869         494 :     destroyPQExpBuffer(nameusing);
   13870             : }
   13871             : 
   13872             : /*
   13873             :  * dumpCollation
   13874             :  *    write out a single collation definition
   13875             :  */
   13876             : static void
   13877        1744 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   13878             : {
   13879        1744 :     DumpOptions *dopt = fout->dopt;
   13880             :     PQExpBuffer query;
   13881             :     PQExpBuffer q;
   13882             :     PQExpBuffer delq;
   13883             :     char       *qcollname;
   13884             :     PGresult   *res;
   13885             :     int         i_collprovider;
   13886             :     int         i_collisdeterministic;
   13887             :     int         i_collcollate;
   13888             :     int         i_collctype;
   13889             :     int         i_colllocale;
   13890             :     int         i_collicurules;
   13891             :     const char *collprovider;
   13892             :     const char *collcollate;
   13893             :     const char *collctype;
   13894             :     const char *colllocale;
   13895             :     const char *collicurules;
   13896             : 
   13897             :     /* Do nothing in data-only dump */
   13898        1744 :     if (dopt->dataOnly)
   13899          12 :         return;
   13900             : 
   13901        1732 :     query = createPQExpBuffer();
   13902        1732 :     q = createPQExpBuffer();
   13903        1732 :     delq = createPQExpBuffer();
   13904             : 
   13905        1732 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   13906             : 
   13907             :     /* Get collation-specific details */
   13908        1732 :     appendPQExpBufferStr(query, "SELECT ");
   13909             : 
   13910        1732 :     if (fout->remoteVersion >= 100000)
   13911        1732 :         appendPQExpBufferStr(query,
   13912             :                              "collprovider, "
   13913             :                              "collversion, ");
   13914             :     else
   13915           0 :         appendPQExpBufferStr(query,
   13916             :                              "'c' AS collprovider, "
   13917             :                              "NULL AS collversion, ");
   13918             : 
   13919        1732 :     if (fout->remoteVersion >= 120000)
   13920        1732 :         appendPQExpBufferStr(query,
   13921             :                              "collisdeterministic, ");
   13922             :     else
   13923           0 :         appendPQExpBufferStr(query,
   13924             :                              "true AS collisdeterministic, ");
   13925             : 
   13926        1732 :     if (fout->remoteVersion >= 170000)
   13927        1732 :         appendPQExpBufferStr(query,
   13928             :                              "colllocale, ");
   13929           0 :     else if (fout->remoteVersion >= 150000)
   13930           0 :         appendPQExpBufferStr(query,
   13931             :                              "colliculocale AS colllocale, ");
   13932             :     else
   13933           0 :         appendPQExpBufferStr(query,
   13934             :                              "NULL AS colllocale, ");
   13935             : 
   13936        1732 :     if (fout->remoteVersion >= 160000)
   13937        1732 :         appendPQExpBufferStr(query,
   13938             :                              "collicurules, ");
   13939             :     else
   13940           0 :         appendPQExpBufferStr(query,
   13941             :                              "NULL AS collicurules, ");
   13942             : 
   13943        1732 :     appendPQExpBuffer(query,
   13944             :                       "collcollate, "
   13945             :                       "collctype "
   13946             :                       "FROM pg_catalog.pg_collation c "
   13947             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   13948             :                       collinfo->dobj.catId.oid);
   13949             : 
   13950        1732 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13951             : 
   13952        1732 :     i_collprovider = PQfnumber(res, "collprovider");
   13953        1732 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   13954        1732 :     i_collcollate = PQfnumber(res, "collcollate");
   13955        1732 :     i_collctype = PQfnumber(res, "collctype");
   13956        1732 :     i_colllocale = PQfnumber(res, "colllocale");
   13957        1732 :     i_collicurules = PQfnumber(res, "collicurules");
   13958             : 
   13959        1732 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   13960             : 
   13961        1732 :     if (!PQgetisnull(res, 0, i_collcollate))
   13962          74 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   13963             :     else
   13964        1658 :         collcollate = NULL;
   13965             : 
   13966        1732 :     if (!PQgetisnull(res, 0, i_collctype))
   13967          74 :         collctype = PQgetvalue(res, 0, i_collctype);
   13968             :     else
   13969        1658 :         collctype = NULL;
   13970             : 
   13971             :     /*
   13972             :      * Before version 15, collcollate and collctype were of type NAME and
   13973             :      * non-nullable. Treat empty strings as NULL for consistency.
   13974             :      */
   13975        1732 :     if (fout->remoteVersion < 150000)
   13976             :     {
   13977           0 :         if (collcollate[0] == '\0')
   13978           0 :             collcollate = NULL;
   13979           0 :         if (collctype[0] == '\0')
   13980           0 :             collctype = NULL;
   13981             :     }
   13982             : 
   13983        1732 :     if (!PQgetisnull(res, 0, i_colllocale))
   13984        1656 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   13985             :     else
   13986          76 :         colllocale = NULL;
   13987             : 
   13988        1732 :     if (!PQgetisnull(res, 0, i_collicurules))
   13989           0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   13990             :     else
   13991        1732 :         collicurules = NULL;
   13992             : 
   13993        1732 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   13994        1732 :                       fmtQualifiedDumpable(collinfo));
   13995             : 
   13996        1732 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   13997        1732 :                       fmtQualifiedDumpable(collinfo));
   13998             : 
   13999        1732 :     appendPQExpBufferStr(q, "provider = ");
   14000        1732 :     if (collprovider[0] == 'b')
   14001          14 :         appendPQExpBufferStr(q, "builtin");
   14002        1718 :     else if (collprovider[0] == 'c')
   14003          74 :         appendPQExpBufferStr(q, "libc");
   14004        1644 :     else if (collprovider[0] == 'i')
   14005        1642 :         appendPQExpBufferStr(q, "icu");
   14006           2 :     else if (collprovider[0] == 'd')
   14007             :         /* to allow dumping pg_catalog; not accepted on input */
   14008           2 :         appendPQExpBufferStr(q, "default");
   14009             :     else
   14010           0 :         pg_fatal("unrecognized collation provider: %s",
   14011             :                  collprovider);
   14012             : 
   14013        1732 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   14014           0 :         appendPQExpBufferStr(q, ", deterministic = false");
   14015             : 
   14016        1732 :     if (collprovider[0] == 'd')
   14017             :     {
   14018           2 :         if (collcollate || collctype || colllocale || collicurules)
   14019           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14020             : 
   14021             :         /* no locale -- the default collation cannot be reloaded anyway */
   14022             :     }
   14023        1730 :     else if (collprovider[0] == 'b')
   14024             :     {
   14025          14 :         if (collcollate || collctype || !colllocale || collicurules)
   14026           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14027             : 
   14028          14 :         appendPQExpBufferStr(q, ", locale = ");
   14029          14 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   14030             :                               fout);
   14031             :     }
   14032        1716 :     else if (collprovider[0] == 'i')
   14033             :     {
   14034        1642 :         if (fout->remoteVersion >= 150000)
   14035             :         {
   14036        1642 :             if (collcollate || collctype || !colllocale)
   14037           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   14038             : 
   14039        1642 :             appendPQExpBufferStr(q, ", locale = ");
   14040        1642 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   14041             :                                   fout);
   14042             :         }
   14043             :         else
   14044             :         {
   14045           0 :             if (!collcollate || !collctype || colllocale ||
   14046           0 :                 strcmp(collcollate, collctype) != 0)
   14047           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   14048             : 
   14049           0 :             appendPQExpBufferStr(q, ", locale = ");
   14050           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14051             :         }
   14052             : 
   14053        1642 :         if (collicurules)
   14054             :         {
   14055           0 :             appendPQExpBufferStr(q, ", rules = ");
   14056           0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   14057             :         }
   14058             :     }
   14059          74 :     else if (collprovider[0] == 'c')
   14060             :     {
   14061          74 :         if (colllocale || collicurules || !collcollate || !collctype)
   14062           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14063             : 
   14064          74 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   14065             :         {
   14066          74 :             appendPQExpBufferStr(q, ", locale = ");
   14067          74 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14068             :         }
   14069             :         else
   14070             :         {
   14071           0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   14072           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14073           0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   14074           0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   14075             :         }
   14076             :     }
   14077             :     else
   14078           0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   14079             : 
   14080             :     /*
   14081             :      * For binary upgrade, carry over the collation version.  For normal
   14082             :      * dump/restore, omit the version, so that it is computed upon restore.
   14083             :      */
   14084        1732 :     if (dopt->binary_upgrade)
   14085             :     {
   14086             :         int         i_collversion;
   14087             : 
   14088           8 :         i_collversion = PQfnumber(res, "collversion");
   14089           8 :         if (!PQgetisnull(res, 0, i_collversion))
   14090             :         {
   14091           6 :             appendPQExpBufferStr(q, ", version = ");
   14092           6 :             appendStringLiteralAH(q,
   14093             :                                   PQgetvalue(res, 0, i_collversion),
   14094             :                                   fout);
   14095             :         }
   14096             :     }
   14097             : 
   14098        1732 :     appendPQExpBufferStr(q, ");\n");
   14099             : 
   14100        1732 :     if (dopt->binary_upgrade)
   14101           8 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   14102             :                                         "COLLATION", qcollname,
   14103           8 :                                         collinfo->dobj.namespace->dobj.name);
   14104             : 
   14105        1732 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14106        1732 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   14107        1732 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   14108             :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   14109             :                                   .owner = collinfo->rolname,
   14110             :                                   .description = "COLLATION",
   14111             :                                   .section = SECTION_PRE_DATA,
   14112             :                                   .createStmt = q->data,
   14113             :                                   .dropStmt = delq->data));
   14114             : 
   14115             :     /* Dump Collation Comments */
   14116        1732 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14117        1620 :         dumpComment(fout, "COLLATION", qcollname,
   14118        1620 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   14119             :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   14120             : 
   14121        1732 :     PQclear(res);
   14122             : 
   14123        1732 :     destroyPQExpBuffer(query);
   14124        1732 :     destroyPQExpBuffer(q);
   14125        1732 :     destroyPQExpBuffer(delq);
   14126        1732 :     free(qcollname);
   14127             : }
   14128             : 
   14129             : /*
   14130             :  * dumpConversion
   14131             :  *    write out a single conversion definition
   14132             :  */
   14133             : static void
   14134         328 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   14135             : {
   14136         328 :     DumpOptions *dopt = fout->dopt;
   14137             :     PQExpBuffer query;
   14138             :     PQExpBuffer q;
   14139             :     PQExpBuffer delq;
   14140             :     char       *qconvname;
   14141             :     PGresult   *res;
   14142             :     int         i_conforencoding;
   14143             :     int         i_contoencoding;
   14144             :     int         i_conproc;
   14145             :     int         i_condefault;
   14146             :     const char *conforencoding;
   14147             :     const char *contoencoding;
   14148             :     const char *conproc;
   14149             :     bool        condefault;
   14150             : 
   14151             :     /* Do nothing in data-only dump */
   14152         328 :     if (dopt->dataOnly)
   14153           6 :         return;
   14154             : 
   14155         322 :     query = createPQExpBuffer();
   14156         322 :     q = createPQExpBuffer();
   14157         322 :     delq = createPQExpBuffer();
   14158             : 
   14159         322 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   14160             : 
   14161             :     /* Get conversion-specific details */
   14162         322 :     appendPQExpBuffer(query, "SELECT "
   14163             :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   14164             :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   14165             :                       "conproc, condefault "
   14166             :                       "FROM pg_catalog.pg_conversion c "
   14167             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14168             :                       convinfo->dobj.catId.oid);
   14169             : 
   14170         322 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14171             : 
   14172         322 :     i_conforencoding = PQfnumber(res, "conforencoding");
   14173         322 :     i_contoencoding = PQfnumber(res, "contoencoding");
   14174         322 :     i_conproc = PQfnumber(res, "conproc");
   14175         322 :     i_condefault = PQfnumber(res, "condefault");
   14176             : 
   14177         322 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   14178         322 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   14179         322 :     conproc = PQgetvalue(res, 0, i_conproc);
   14180         322 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   14181             : 
   14182         322 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   14183         322 :                       fmtQualifiedDumpable(convinfo));
   14184             : 
   14185         322 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   14186             :                       (condefault) ? "DEFAULT " : "",
   14187         322 :                       fmtQualifiedDumpable(convinfo));
   14188         322 :     appendStringLiteralAH(q, conforencoding, fout);
   14189         322 :     appendPQExpBufferStr(q, " TO ");
   14190         322 :     appendStringLiteralAH(q, contoencoding, fout);
   14191             :     /* regproc output is already sufficiently quoted */
   14192         322 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   14193             : 
   14194         322 :     if (dopt->binary_upgrade)
   14195           2 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   14196             :                                         "CONVERSION", qconvname,
   14197           2 :                                         convinfo->dobj.namespace->dobj.name);
   14198             : 
   14199         322 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14200         322 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   14201         322 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   14202             :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   14203             :                                   .owner = convinfo->rolname,
   14204             :                                   .description = "CONVERSION",
   14205             :                                   .section = SECTION_PRE_DATA,
   14206             :                                   .createStmt = q->data,
   14207             :                                   .dropStmt = delq->data));
   14208             : 
   14209             :     /* Dump Conversion Comments */
   14210         322 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14211         322 :         dumpComment(fout, "CONVERSION", qconvname,
   14212         322 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   14213             :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   14214             : 
   14215         322 :     PQclear(res);
   14216             : 
   14217         322 :     destroyPQExpBuffer(query);
   14218         322 :     destroyPQExpBuffer(q);
   14219         322 :     destroyPQExpBuffer(delq);
   14220         322 :     free(qconvname);
   14221             : }
   14222             : 
   14223             : /*
   14224             :  * format_aggregate_signature: generate aggregate name and argument list
   14225             :  *
   14226             :  * The argument type names are qualified if needed.  The aggregate name
   14227             :  * is never qualified.
   14228             :  */
   14229             : static char *
   14230         572 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   14231             : {
   14232             :     PQExpBufferData buf;
   14233             :     int         j;
   14234             : 
   14235         572 :     initPQExpBuffer(&buf);
   14236         572 :     if (honor_quotes)
   14237           0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   14238             :     else
   14239         572 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   14240             : 
   14241         572 :     if (agginfo->aggfn.nargs == 0)
   14242          80 :         appendPQExpBufferStr(&buf, "(*)");
   14243             :     else
   14244             :     {
   14245         492 :         appendPQExpBufferChar(&buf, '(');
   14246        1074 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   14247         582 :             appendPQExpBuffer(&buf, "%s%s",
   14248             :                               (j > 0) ? ", " : "",
   14249             :                               getFormattedTypeName(fout,
   14250         582 :                                                    agginfo->aggfn.argtypes[j],
   14251             :                                                    zeroIsError));
   14252         492 :         appendPQExpBufferChar(&buf, ')');
   14253             :     }
   14254         572 :     return buf.data;
   14255             : }
   14256             : 
   14257             : /*
   14258             :  * dumpAgg
   14259             :  *    write out a single aggregate definition
   14260             :  */
   14261             : static void
   14262         580 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   14263             : {
   14264         580 :     DumpOptions *dopt = fout->dopt;
   14265             :     PQExpBuffer query;
   14266             :     PQExpBuffer q;
   14267             :     PQExpBuffer delq;
   14268             :     PQExpBuffer details;
   14269             :     char       *aggsig;         /* identity signature */
   14270         580 :     char       *aggfullsig = NULL;  /* full signature */
   14271             :     char       *aggsig_tag;
   14272             :     PGresult   *res;
   14273             :     int         i_agginitval;
   14274             :     int         i_aggminitval;
   14275             :     const char *aggtransfn;
   14276             :     const char *aggfinalfn;
   14277             :     const char *aggcombinefn;
   14278             :     const char *aggserialfn;
   14279             :     const char *aggdeserialfn;
   14280             :     const char *aggmtransfn;
   14281             :     const char *aggminvtransfn;
   14282             :     const char *aggmfinalfn;
   14283             :     bool        aggfinalextra;
   14284             :     bool        aggmfinalextra;
   14285             :     char        aggfinalmodify;
   14286             :     char        aggmfinalmodify;
   14287             :     const char *aggsortop;
   14288             :     char       *aggsortconvop;
   14289             :     char        aggkind;
   14290             :     const char *aggtranstype;
   14291             :     const char *aggtransspace;
   14292             :     const char *aggmtranstype;
   14293             :     const char *aggmtransspace;
   14294             :     const char *agginitval;
   14295             :     const char *aggminitval;
   14296             :     const char *proparallel;
   14297             :     char        defaultfinalmodify;
   14298             : 
   14299             :     /* Do nothing in data-only dump */
   14300         580 :     if (dopt->dataOnly)
   14301           8 :         return;
   14302             : 
   14303         572 :     query = createPQExpBuffer();
   14304         572 :     q = createPQExpBuffer();
   14305         572 :     delq = createPQExpBuffer();
   14306         572 :     details = createPQExpBuffer();
   14307             : 
   14308         572 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   14309             :     {
   14310             :         /* Set up query for aggregate-specific details */
   14311         112 :         appendPQExpBufferStr(query,
   14312             :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   14313             : 
   14314         112 :         appendPQExpBufferStr(query,
   14315             :                              "SELECT "
   14316             :                              "aggtransfn,\n"
   14317             :                              "aggfinalfn,\n"
   14318             :                              "aggtranstype::pg_catalog.regtype,\n"
   14319             :                              "agginitval,\n"
   14320             :                              "aggsortop,\n"
   14321             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   14322             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   14323             : 
   14324         112 :         if (fout->remoteVersion >= 90400)
   14325         112 :             appendPQExpBufferStr(query,
   14326             :                                  "aggkind,\n"
   14327             :                                  "aggmtransfn,\n"
   14328             :                                  "aggminvtransfn,\n"
   14329             :                                  "aggmfinalfn,\n"
   14330             :                                  "aggmtranstype::pg_catalog.regtype,\n"
   14331             :                                  "aggfinalextra,\n"
   14332             :                                  "aggmfinalextra,\n"
   14333             :                                  "aggtransspace,\n"
   14334             :                                  "aggmtransspace,\n"
   14335             :                                  "aggminitval,\n");
   14336             :         else
   14337           0 :             appendPQExpBufferStr(query,
   14338             :                                  "'n' AS aggkind,\n"
   14339             :                                  "'-' AS aggmtransfn,\n"
   14340             :                                  "'-' AS aggminvtransfn,\n"
   14341             :                                  "'-' AS aggmfinalfn,\n"
   14342             :                                  "0 AS aggmtranstype,\n"
   14343             :                                  "false AS aggfinalextra,\n"
   14344             :                                  "false AS aggmfinalextra,\n"
   14345             :                                  "0 AS aggtransspace,\n"
   14346             :                                  "0 AS aggmtransspace,\n"
   14347             :                                  "NULL AS aggminitval,\n");
   14348             : 
   14349         112 :         if (fout->remoteVersion >= 90600)
   14350         112 :             appendPQExpBufferStr(query,
   14351             :                                  "aggcombinefn,\n"
   14352             :                                  "aggserialfn,\n"
   14353             :                                  "aggdeserialfn,\n"
   14354             :                                  "proparallel,\n");
   14355             :         else
   14356           0 :             appendPQExpBufferStr(query,
   14357             :                                  "'-' AS aggcombinefn,\n"
   14358             :                                  "'-' AS aggserialfn,\n"
   14359             :                                  "'-' AS aggdeserialfn,\n"
   14360             :                                  "'u' AS proparallel,\n");
   14361             : 
   14362         112 :         if (fout->remoteVersion >= 110000)
   14363         112 :             appendPQExpBufferStr(query,
   14364             :                                  "aggfinalmodify,\n"
   14365             :                                  "aggmfinalmodify\n");
   14366             :         else
   14367           0 :             appendPQExpBufferStr(query,
   14368             :                                  "'0' AS aggfinalmodify,\n"
   14369             :                                  "'0' AS aggmfinalmodify\n");
   14370             : 
   14371         112 :         appendPQExpBufferStr(query,
   14372             :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   14373             :                              "WHERE a.aggfnoid = p.oid "
   14374             :                              "AND p.oid = $1");
   14375             : 
   14376         112 :         ExecuteSqlStatement(fout, query->data);
   14377             : 
   14378         112 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   14379             :     }
   14380             : 
   14381         572 :     printfPQExpBuffer(query,
   14382             :                       "EXECUTE dumpAgg('%u')",
   14383             :                       agginfo->aggfn.dobj.catId.oid);
   14384             : 
   14385         572 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14386             : 
   14387         572 :     i_agginitval = PQfnumber(res, "agginitval");
   14388         572 :     i_aggminitval = PQfnumber(res, "aggminitval");
   14389             : 
   14390         572 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   14391         572 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   14392         572 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   14393         572 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   14394         572 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   14395         572 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   14396         572 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   14397         572 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   14398         572 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   14399         572 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   14400         572 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   14401         572 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   14402         572 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   14403         572 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   14404         572 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   14405         572 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   14406         572 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   14407         572 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   14408         572 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   14409         572 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   14410         572 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   14411             : 
   14412             :     {
   14413             :         char       *funcargs;
   14414             :         char       *funciargs;
   14415             : 
   14416         572 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   14417         572 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   14418         572 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   14419         572 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   14420             :     }
   14421             : 
   14422         572 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   14423             : 
   14424             :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   14425         572 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   14426             :     /* replace omitted flags for old versions */
   14427         572 :     if (aggfinalmodify == '0')
   14428           0 :         aggfinalmodify = defaultfinalmodify;
   14429         572 :     if (aggmfinalmodify == '0')
   14430           0 :         aggmfinalmodify = defaultfinalmodify;
   14431             : 
   14432             :     /* regproc and regtype output is already sufficiently quoted */
   14433         572 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   14434             :                       aggtransfn, aggtranstype);
   14435             : 
   14436         572 :     if (strcmp(aggtransspace, "0") != 0)
   14437             :     {
   14438          10 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   14439             :                           aggtransspace);
   14440             :     }
   14441             : 
   14442         572 :     if (!PQgetisnull(res, 0, i_agginitval))
   14443             :     {
   14444         416 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   14445         416 :         appendStringLiteralAH(details, agginitval, fout);
   14446             :     }
   14447             : 
   14448         572 :     if (strcmp(aggfinalfn, "-") != 0)
   14449             :     {
   14450         266 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   14451             :                           aggfinalfn);
   14452         266 :         if (aggfinalextra)
   14453          20 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   14454         266 :         if (aggfinalmodify != defaultfinalmodify)
   14455             :         {
   14456          66 :             switch (aggfinalmodify)
   14457             :             {
   14458           0 :                 case AGGMODIFY_READ_ONLY:
   14459           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   14460           0 :                     break;
   14461          66 :                 case AGGMODIFY_SHAREABLE:
   14462          66 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   14463          66 :                     break;
   14464           0 :                 case AGGMODIFY_READ_WRITE:
   14465           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   14466           0 :                     break;
   14467           0 :                 default:
   14468           0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   14469             :                              agginfo->aggfn.dobj.name);
   14470             :                     break;
   14471             :             }
   14472         506 :         }
   14473             :     }
   14474             : 
   14475         572 :     if (strcmp(aggcombinefn, "-") != 0)
   14476           0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   14477             : 
   14478         572 :     if (strcmp(aggserialfn, "-") != 0)
   14479           0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   14480             : 
   14481         572 :     if (strcmp(aggdeserialfn, "-") != 0)
   14482           0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   14483             : 
   14484         572 :     if (strcmp(aggmtransfn, "-") != 0)
   14485             :     {
   14486          60 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   14487             :                           aggmtransfn,
   14488             :                           aggminvtransfn,
   14489             :                           aggmtranstype);
   14490             :     }
   14491             : 
   14492         572 :     if (strcmp(aggmtransspace, "0") != 0)
   14493             :     {
   14494           0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   14495             :                           aggmtransspace);
   14496             :     }
   14497             : 
   14498         572 :     if (!PQgetisnull(res, 0, i_aggminitval))
   14499             :     {
   14500          20 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   14501          20 :         appendStringLiteralAH(details, aggminitval, fout);
   14502             :     }
   14503             : 
   14504         572 :     if (strcmp(aggmfinalfn, "-") != 0)
   14505             :     {
   14506           0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   14507             :                           aggmfinalfn);
   14508           0 :         if (aggmfinalextra)
   14509           0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   14510           0 :         if (aggmfinalmodify != defaultfinalmodify)
   14511             :         {
   14512           0 :             switch (aggmfinalmodify)
   14513             :             {
   14514           0 :                 case AGGMODIFY_READ_ONLY:
   14515           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   14516           0 :                     break;
   14517           0 :                 case AGGMODIFY_SHAREABLE:
   14518           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   14519           0 :                     break;
   14520           0 :                 case AGGMODIFY_READ_WRITE:
   14521           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   14522           0 :                     break;
   14523           0 :                 default:
   14524           0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   14525             :                              agginfo->aggfn.dobj.name);
   14526             :                     break;
   14527             :             }
   14528         572 :         }
   14529             :     }
   14530             : 
   14531         572 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   14532         572 :     if (aggsortconvop)
   14533             :     {
   14534           0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   14535             :                           aggsortconvop);
   14536           0 :         free(aggsortconvop);
   14537             :     }
   14538             : 
   14539         572 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   14540          10 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   14541             : 
   14542         572 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   14543             :     {
   14544          10 :         if (proparallel[0] == PROPARALLEL_SAFE)
   14545          10 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   14546           0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   14547           0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   14548           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   14549           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   14550             :                      agginfo->aggfn.dobj.name);
   14551             :     }
   14552             : 
   14553         572 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   14554         572 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   14555             :                       aggsig);
   14556             : 
   14557        1144 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   14558         572 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   14559             :                       aggfullsig ? aggfullsig : aggsig, details->data);
   14560             : 
   14561         572 :     if (dopt->binary_upgrade)
   14562          98 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   14563             :                                         "AGGREGATE", aggsig,
   14564          98 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   14565             : 
   14566         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   14567         538 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   14568             :                      agginfo->aggfn.dobj.dumpId,
   14569         538 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   14570             :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   14571             :                                   .owner = agginfo->aggfn.rolname,
   14572             :                                   .description = "AGGREGATE",
   14573             :                                   .section = SECTION_PRE_DATA,
   14574             :                                   .createStmt = q->data,
   14575             :                                   .dropStmt = delq->data));
   14576             : 
   14577             :     /* Dump Aggregate Comments */
   14578         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   14579          20 :         dumpComment(fout, "AGGREGATE", aggsig,
   14580          20 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   14581             :                     agginfo->aggfn.rolname,
   14582             :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   14583             : 
   14584         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   14585           0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   14586           0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   14587             :                      agginfo->aggfn.rolname,
   14588             :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   14589             : 
   14590             :     /*
   14591             :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   14592             :      * command look like a function's GRANT; in particular this affects the
   14593             :      * syntax for zero-argument aggregates and ordered-set aggregates.
   14594             :      */
   14595         572 :     free(aggsig);
   14596             : 
   14597         572 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   14598             : 
   14599         572 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   14600          36 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   14601             :                 "FUNCTION", aggsig, NULL,
   14602          36 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   14603             :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   14604             : 
   14605         572 :     free(aggsig);
   14606         572 :     free(aggfullsig);
   14607         572 :     free(aggsig_tag);
   14608             : 
   14609         572 :     PQclear(res);
   14610             : 
   14611         572 :     destroyPQExpBuffer(query);
   14612         572 :     destroyPQExpBuffer(q);
   14613         572 :     destroyPQExpBuffer(delq);
   14614         572 :     destroyPQExpBuffer(details);
   14615             : }
   14616             : 
   14617             : /*
   14618             :  * dumpTSParser
   14619             :  *    write out a single text search parser
   14620             :  */
   14621             : static void
   14622          74 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   14623             : {
   14624          74 :     DumpOptions *dopt = fout->dopt;
   14625             :     PQExpBuffer q;
   14626             :     PQExpBuffer delq;
   14627             :     char       *qprsname;
   14628             : 
   14629             :     /* Do nothing in data-only dump */
   14630          74 :     if (dopt->dataOnly)
   14631           6 :         return;
   14632             : 
   14633          68 :     q = createPQExpBuffer();
   14634          68 :     delq = createPQExpBuffer();
   14635             : 
   14636          68 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   14637             : 
   14638          68 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   14639          68 :                       fmtQualifiedDumpable(prsinfo));
   14640             : 
   14641          68 :     appendPQExpBuffer(q, "    START = %s,\n",
   14642             :                       convertTSFunction(fout, prsinfo->prsstart));
   14643          68 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   14644             :                       convertTSFunction(fout, prsinfo->prstoken));
   14645          68 :     appendPQExpBuffer(q, "    END = %s,\n",
   14646             :                       convertTSFunction(fout, prsinfo->prsend));
   14647          68 :     if (prsinfo->prsheadline != InvalidOid)
   14648           2 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   14649             :                           convertTSFunction(fout, prsinfo->prsheadline));
   14650          68 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   14651             :                       convertTSFunction(fout, prsinfo->prslextype));
   14652             : 
   14653          68 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   14654          68 :                       fmtQualifiedDumpable(prsinfo));
   14655             : 
   14656          68 :     if (dopt->binary_upgrade)
   14657           2 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   14658             :                                         "TEXT SEARCH PARSER", qprsname,
   14659           2 :                                         prsinfo->dobj.namespace->dobj.name);
   14660             : 
   14661          68 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14662          68 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   14663          68 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   14664             :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   14665             :                                   .description = "TEXT SEARCH PARSER",
   14666             :                                   .section = SECTION_PRE_DATA,
   14667             :                                   .createStmt = q->data,
   14668             :                                   .dropStmt = delq->data));
   14669             : 
   14670             :     /* Dump Parser Comments */
   14671          68 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14672          68 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   14673          68 :                     prsinfo->dobj.namespace->dobj.name, "",
   14674             :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   14675             : 
   14676          68 :     destroyPQExpBuffer(q);
   14677          68 :     destroyPQExpBuffer(delq);
   14678          68 :     free(qprsname);
   14679             : }
   14680             : 
   14681             : /*
   14682             :  * dumpTSDictionary
   14683             :  *    write out a single text search dictionary
   14684             :  */
   14685             : static void
   14686         220 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   14687             : {
   14688         220 :     DumpOptions *dopt = fout->dopt;
   14689             :     PQExpBuffer q;
   14690             :     PQExpBuffer delq;
   14691             :     PQExpBuffer query;
   14692             :     char       *qdictname;
   14693             :     PGresult   *res;
   14694             :     char       *nspname;
   14695             :     char       *tmplname;
   14696             : 
   14697             :     /* Do nothing in data-only dump */
   14698         220 :     if (dopt->dataOnly)
   14699           6 :         return;
   14700             : 
   14701         214 :     q = createPQExpBuffer();
   14702         214 :     delq = createPQExpBuffer();
   14703         214 :     query = createPQExpBuffer();
   14704             : 
   14705         214 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   14706             : 
   14707             :     /* Fetch name and namespace of the dictionary's template */
   14708         214 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   14709             :                       "FROM pg_ts_template p, pg_namespace n "
   14710             :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   14711             :                       dictinfo->dicttemplate);
   14712         214 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14713         214 :     nspname = PQgetvalue(res, 0, 0);
   14714         214 :     tmplname = PQgetvalue(res, 0, 1);
   14715             : 
   14716         214 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   14717         214 :                       fmtQualifiedDumpable(dictinfo));
   14718             : 
   14719         214 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   14720         214 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   14721         214 :     appendPQExpBufferStr(q, fmtId(tmplname));
   14722             : 
   14723         214 :     PQclear(res);
   14724             : 
   14725             :     /* the dictinitoption can be dumped straight into the command */
   14726         214 :     if (dictinfo->dictinitoption)
   14727         146 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   14728             : 
   14729         214 :     appendPQExpBufferStr(q, " );\n");
   14730             : 
   14731         214 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   14732         214 :                       fmtQualifiedDumpable(dictinfo));
   14733             : 
   14734         214 :     if (dopt->binary_upgrade)
   14735          20 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   14736             :                                         "TEXT SEARCH DICTIONARY", qdictname,
   14737          20 :                                         dictinfo->dobj.namespace->dobj.name);
   14738             : 
   14739         214 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14740         214 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   14741         214 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   14742             :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   14743             :                                   .owner = dictinfo->rolname,
   14744             :                                   .description = "TEXT SEARCH DICTIONARY",
   14745             :                                   .section = SECTION_PRE_DATA,
   14746             :                                   .createStmt = q->data,
   14747             :                                   .dropStmt = delq->data));
   14748             : 
   14749             :     /* Dump Dictionary Comments */
   14750         214 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14751         124 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   14752         124 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   14753             :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   14754             : 
   14755         214 :     destroyPQExpBuffer(q);
   14756         214 :     destroyPQExpBuffer(delq);
   14757         214 :     destroyPQExpBuffer(query);
   14758         214 :     free(qdictname);
   14759             : }
   14760             : 
   14761             : /*
   14762             :  * dumpTSTemplate
   14763             :  *    write out a single text search template
   14764             :  */
   14765             : static void
   14766          82 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   14767             : {
   14768          82 :     DumpOptions *dopt = fout->dopt;
   14769             :     PQExpBuffer q;
   14770             :     PQExpBuffer delq;
   14771             :     char       *qtmplname;
   14772             : 
   14773             :     /* Do nothing in data-only dump */
   14774          82 :     if (dopt->dataOnly)
   14775           6 :         return;
   14776             : 
   14777          76 :     q = createPQExpBuffer();
   14778          76 :     delq = createPQExpBuffer();
   14779             : 
   14780          76 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   14781             : 
   14782          76 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   14783          76 :                       fmtQualifiedDumpable(tmplinfo));
   14784             : 
   14785          76 :     if (tmplinfo->tmplinit != InvalidOid)
   14786          10 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   14787             :                           convertTSFunction(fout, tmplinfo->tmplinit));
   14788          76 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   14789             :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   14790             : 
   14791          76 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   14792          76 :                       fmtQualifiedDumpable(tmplinfo));
   14793             : 
   14794          76 :     if (dopt->binary_upgrade)
   14795           2 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   14796             :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   14797           2 :                                         tmplinfo->dobj.namespace->dobj.name);
   14798             : 
   14799          76 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14800          76 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   14801          76 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   14802             :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   14803             :                                   .description = "TEXT SEARCH TEMPLATE",
   14804             :                                   .section = SECTION_PRE_DATA,
   14805             :                                   .createStmt = q->data,
   14806             :                                   .dropStmt = delq->data));
   14807             : 
   14808             :     /* Dump Template Comments */
   14809          76 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14810          76 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   14811          76 :                     tmplinfo->dobj.namespace->dobj.name, "",
   14812             :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   14813             : 
   14814          76 :     destroyPQExpBuffer(q);
   14815          76 :     destroyPQExpBuffer(delq);
   14816          76 :     free(qtmplname);
   14817             : }
   14818             : 
   14819             : /*
   14820             :  * dumpTSConfig
   14821             :  *    write out a single text search configuration
   14822             :  */
   14823             : static void
   14824         170 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   14825             : {
   14826         170 :     DumpOptions *dopt = fout->dopt;
   14827             :     PQExpBuffer q;
   14828             :     PQExpBuffer delq;
   14829             :     PQExpBuffer query;
   14830             :     char       *qcfgname;
   14831             :     PGresult   *res;
   14832             :     char       *nspname;
   14833             :     char       *prsname;
   14834             :     int         ntups,
   14835             :                 i;
   14836             :     int         i_tokenname;
   14837             :     int         i_dictname;
   14838             : 
   14839             :     /* Do nothing in data-only dump */
   14840         170 :     if (dopt->dataOnly)
   14841           6 :         return;
   14842             : 
   14843         164 :     q = createPQExpBuffer();
   14844         164 :     delq = createPQExpBuffer();
   14845         164 :     query = createPQExpBuffer();
   14846             : 
   14847         164 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   14848             : 
   14849             :     /* Fetch name and namespace of the config's parser */
   14850         164 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   14851             :                       "FROM pg_ts_parser p, pg_namespace n "
   14852             :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   14853             :                       cfginfo->cfgparser);
   14854         164 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14855         164 :     nspname = PQgetvalue(res, 0, 0);
   14856         164 :     prsname = PQgetvalue(res, 0, 1);
   14857             : 
   14858         164 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   14859         164 :                       fmtQualifiedDumpable(cfginfo));
   14860             : 
   14861         164 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   14862         164 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   14863             : 
   14864         164 :     PQclear(res);
   14865             : 
   14866         164 :     resetPQExpBuffer(query);
   14867         164 :     appendPQExpBuffer(query,
   14868             :                       "SELECT\n"
   14869             :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   14870             :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   14871             :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   14872             :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   14873             :                       "WHERE m.mapcfg = '%u'\n"
   14874             :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   14875             :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   14876             : 
   14877         164 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14878         164 :     ntups = PQntuples(res);
   14879             : 
   14880         164 :     i_tokenname = PQfnumber(res, "tokenname");
   14881         164 :     i_dictname = PQfnumber(res, "dictname");
   14882             : 
   14883        3550 :     for (i = 0; i < ntups; i++)
   14884             :     {
   14885        3386 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   14886        3386 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   14887             : 
   14888        3386 :         if (i == 0 ||
   14889        3222 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   14890             :         {
   14891             :             /* starting a new token type, so start a new command */
   14892        3116 :             if (i > 0)
   14893        2952 :                 appendPQExpBufferStr(q, ";\n");
   14894        3116 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   14895        3116 :                               fmtQualifiedDumpable(cfginfo));
   14896             :             /* tokenname needs quoting, dictname does NOT */
   14897        3116 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   14898             :                               fmtId(tokenname), dictname);
   14899             :         }
   14900             :         else
   14901         270 :             appendPQExpBuffer(q, ", %s", dictname);
   14902             :     }
   14903             : 
   14904         164 :     if (ntups > 0)
   14905         164 :         appendPQExpBufferStr(q, ";\n");
   14906             : 
   14907         164 :     PQclear(res);
   14908             : 
   14909         164 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   14910         164 :                       fmtQualifiedDumpable(cfginfo));
   14911             : 
   14912         164 :     if (dopt->binary_upgrade)
   14913          10 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   14914             :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   14915          10 :                                         cfginfo->dobj.namespace->dobj.name);
   14916             : 
   14917         164 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14918         164 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   14919         164 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   14920             :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   14921             :                                   .owner = cfginfo->rolname,
   14922             :                                   .description = "TEXT SEARCH CONFIGURATION",
   14923             :                                   .section = SECTION_PRE_DATA,
   14924             :                                   .createStmt = q->data,
   14925             :                                   .dropStmt = delq->data));
   14926             : 
   14927             :     /* Dump Configuration Comments */
   14928         164 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14929         124 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   14930         124 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   14931             :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   14932             : 
   14933         164 :     destroyPQExpBuffer(q);
   14934         164 :     destroyPQExpBuffer(delq);
   14935         164 :     destroyPQExpBuffer(query);
   14936         164 :     free(qcfgname);
   14937             : }
   14938             : 
   14939             : /*
   14940             :  * dumpForeignDataWrapper
   14941             :  *    write out a single foreign-data wrapper definition
   14942             :  */
   14943             : static void
   14944         100 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   14945             : {
   14946         100 :     DumpOptions *dopt = fout->dopt;
   14947             :     PQExpBuffer q;
   14948             :     PQExpBuffer delq;
   14949             :     char       *qfdwname;
   14950             : 
   14951             :     /* Do nothing in data-only dump */
   14952         100 :     if (dopt->dataOnly)
   14953           8 :         return;
   14954             : 
   14955          92 :     q = createPQExpBuffer();
   14956          92 :     delq = createPQExpBuffer();
   14957             : 
   14958          92 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   14959             : 
   14960          92 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   14961             :                       qfdwname);
   14962             : 
   14963          92 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   14964           0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   14965             : 
   14966          92 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   14967           0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   14968             : 
   14969          92 :     if (strlen(fdwinfo->fdwoptions) > 0)
   14970           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   14971             : 
   14972          92 :     appendPQExpBufferStr(q, ";\n");
   14973             : 
   14974          92 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   14975             :                       qfdwname);
   14976             : 
   14977          92 :     if (dopt->binary_upgrade)
   14978           4 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   14979             :                                         "FOREIGN DATA WRAPPER", qfdwname,
   14980             :                                         NULL);
   14981             : 
   14982          92 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14983          92 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   14984          92 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   14985             :                                   .owner = fdwinfo->rolname,
   14986             :                                   .description = "FOREIGN DATA WRAPPER",
   14987             :                                   .section = SECTION_PRE_DATA,
   14988             :                                   .createStmt = q->data,
   14989             :                                   .dropStmt = delq->data));
   14990             : 
   14991             :     /* Dump Foreign Data Wrapper Comments */
   14992          92 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14993           0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   14994             :                     NULL, fdwinfo->rolname,
   14995             :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   14996             : 
   14997             :     /* Handle the ACL */
   14998          92 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   14999          64 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   15000             :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   15001             :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   15002             : 
   15003          92 :     free(qfdwname);
   15004             : 
   15005          92 :     destroyPQExpBuffer(q);
   15006          92 :     destroyPQExpBuffer(delq);
   15007             : }
   15008             : 
   15009             : /*
   15010             :  * dumpForeignServer
   15011             :  *    write out a foreign server definition
   15012             :  */
   15013             : static void
   15014         108 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   15015             : {
   15016         108 :     DumpOptions *dopt = fout->dopt;
   15017             :     PQExpBuffer q;
   15018             :     PQExpBuffer delq;
   15019             :     PQExpBuffer query;
   15020             :     PGresult   *res;
   15021             :     char       *qsrvname;
   15022             :     char       *fdwname;
   15023             : 
   15024             :     /* Do nothing in data-only dump */
   15025         108 :     if (dopt->dataOnly)
   15026          12 :         return;
   15027             : 
   15028          96 :     q = createPQExpBuffer();
   15029          96 :     delq = createPQExpBuffer();
   15030          96 :     query = createPQExpBuffer();
   15031             : 
   15032          96 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   15033             : 
   15034             :     /* look up the foreign-data wrapper */
   15035          96 :     appendPQExpBuffer(query, "SELECT fdwname "
   15036             :                       "FROM pg_foreign_data_wrapper w "
   15037             :                       "WHERE w.oid = '%u'",
   15038             :                       srvinfo->srvfdw);
   15039          96 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15040          96 :     fdwname = PQgetvalue(res, 0, 0);
   15041             : 
   15042          96 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   15043          96 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   15044             :     {
   15045           0 :         appendPQExpBufferStr(q, " TYPE ");
   15046           0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   15047             :     }
   15048          96 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   15049             :     {
   15050           0 :         appendPQExpBufferStr(q, " VERSION ");
   15051           0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   15052             :     }
   15053             : 
   15054          96 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   15055          96 :     appendPQExpBufferStr(q, fmtId(fdwname));
   15056             : 
   15057          96 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   15058           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   15059             : 
   15060          96 :     appendPQExpBufferStr(q, ";\n");
   15061             : 
   15062          96 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   15063             :                       qsrvname);
   15064             : 
   15065          96 :     if (dopt->binary_upgrade)
   15066           4 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   15067             :                                         "SERVER", qsrvname, NULL);
   15068             : 
   15069          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15070          96 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   15071          96 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   15072             :                                   .owner = srvinfo->rolname,
   15073             :                                   .description = "SERVER",
   15074             :                                   .section = SECTION_PRE_DATA,
   15075             :                                   .createStmt = q->data,
   15076             :                                   .dropStmt = delq->data));
   15077             : 
   15078             :     /* Dump Foreign Server Comments */
   15079          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15080           0 :         dumpComment(fout, "SERVER", qsrvname,
   15081             :                     NULL, srvinfo->rolname,
   15082             :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   15083             : 
   15084             :     /* Handle the ACL */
   15085          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15086          64 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   15087             :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   15088             :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   15089             : 
   15090             :     /* Dump user mappings */
   15091          96 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   15092          96 :         dumpUserMappings(fout,
   15093          96 :                          srvinfo->dobj.name, NULL,
   15094             :                          srvinfo->rolname,
   15095             :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   15096             : 
   15097          96 :     PQclear(res);
   15098             : 
   15099          96 :     free(qsrvname);
   15100             : 
   15101          96 :     destroyPQExpBuffer(q);
   15102          96 :     destroyPQExpBuffer(delq);
   15103          96 :     destroyPQExpBuffer(query);
   15104             : }
   15105             : 
   15106             : /*
   15107             :  * dumpUserMappings
   15108             :  *
   15109             :  * This routine is used to dump any user mappings associated with the
   15110             :  * server handed to this routine. Should be called after ArchiveEntry()
   15111             :  * for the server.
   15112             :  */
   15113             : static void
   15114          96 : dumpUserMappings(Archive *fout,
   15115             :                  const char *servername, const char *namespace,
   15116             :                  const char *owner,
   15117             :                  CatalogId catalogId, DumpId dumpId)
   15118             : {
   15119             :     PQExpBuffer q;
   15120             :     PQExpBuffer delq;
   15121             :     PQExpBuffer query;
   15122             :     PQExpBuffer tag;
   15123             :     PGresult   *res;
   15124             :     int         ntups;
   15125             :     int         i_usename;
   15126             :     int         i_umoptions;
   15127             :     int         i;
   15128             : 
   15129          96 :     q = createPQExpBuffer();
   15130          96 :     tag = createPQExpBuffer();
   15131          96 :     delq = createPQExpBuffer();
   15132          96 :     query = createPQExpBuffer();
   15133             : 
   15134             :     /*
   15135             :      * We read from the publicly accessible view pg_user_mappings, so as not
   15136             :      * to fail if run by a non-superuser.  Note that the view will show
   15137             :      * umoptions as null if the user hasn't got privileges for the associated
   15138             :      * server; this means that pg_dump will dump such a mapping, but with no
   15139             :      * OPTIONS clause.  A possible alternative is to skip such mappings
   15140             :      * altogether, but it's not clear that that's an improvement.
   15141             :      */
   15142          96 :     appendPQExpBuffer(query,
   15143             :                       "SELECT usename, "
   15144             :                       "array_to_string(ARRAY("
   15145             :                       "SELECT quote_ident(option_name) || ' ' || "
   15146             :                       "quote_literal(option_value) "
   15147             :                       "FROM pg_options_to_table(umoptions) "
   15148             :                       "ORDER BY option_name"
   15149             :                       "), E',\n    ') AS umoptions "
   15150             :                       "FROM pg_user_mappings "
   15151             :                       "WHERE srvid = '%u' "
   15152             :                       "ORDER BY usename",
   15153             :                       catalogId.oid);
   15154             : 
   15155          96 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15156             : 
   15157          96 :     ntups = PQntuples(res);
   15158          96 :     i_usename = PQfnumber(res, "usename");
   15159          96 :     i_umoptions = PQfnumber(res, "umoptions");
   15160             : 
   15161         160 :     for (i = 0; i < ntups; i++)
   15162             :     {
   15163             :         char       *usename;
   15164             :         char       *umoptions;
   15165             : 
   15166          64 :         usename = PQgetvalue(res, i, i_usename);
   15167          64 :         umoptions = PQgetvalue(res, i, i_umoptions);
   15168             : 
   15169          64 :         resetPQExpBuffer(q);
   15170          64 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   15171          64 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   15172             : 
   15173          64 :         if (umoptions && strlen(umoptions) > 0)
   15174           0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   15175             : 
   15176          64 :         appendPQExpBufferStr(q, ";\n");
   15177             : 
   15178          64 :         resetPQExpBuffer(delq);
   15179          64 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   15180          64 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   15181             : 
   15182          64 :         resetPQExpBuffer(tag);
   15183          64 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   15184             :                           usename, servername);
   15185             : 
   15186          64 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15187          64 :                      ARCHIVE_OPTS(.tag = tag->data,
   15188             :                                   .namespace = namespace,
   15189             :                                   .owner = owner,
   15190             :                                   .description = "USER MAPPING",
   15191             :                                   .section = SECTION_PRE_DATA,
   15192             :                                   .createStmt = q->data,
   15193             :                                   .dropStmt = delq->data));
   15194             :     }
   15195             : 
   15196          96 :     PQclear(res);
   15197             : 
   15198          96 :     destroyPQExpBuffer(query);
   15199          96 :     destroyPQExpBuffer(delq);
   15200          96 :     destroyPQExpBuffer(tag);
   15201          96 :     destroyPQExpBuffer(q);
   15202          96 : }
   15203             : 
   15204             : /*
   15205             :  * Write out default privileges information
   15206             :  */
   15207             : static void
   15208         284 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   15209             : {
   15210         284 :     DumpOptions *dopt = fout->dopt;
   15211             :     PQExpBuffer q;
   15212             :     PQExpBuffer tag;
   15213             :     const char *type;
   15214             : 
   15215             :     /* Do nothing in data-only dump, or if we're skipping ACLs */
   15216         284 :     if (dopt->dataOnly || dopt->aclsSkip)
   15217          32 :         return;
   15218             : 
   15219         252 :     q = createPQExpBuffer();
   15220         252 :     tag = createPQExpBuffer();
   15221             : 
   15222         252 :     switch (daclinfo->defaclobjtype)
   15223             :     {
   15224         126 :         case DEFACLOBJ_RELATION:
   15225         126 :             type = "TABLES";
   15226         126 :             break;
   15227           0 :         case DEFACLOBJ_SEQUENCE:
   15228           0 :             type = "SEQUENCES";
   15229           0 :             break;
   15230         126 :         case DEFACLOBJ_FUNCTION:
   15231         126 :             type = "FUNCTIONS";
   15232         126 :             break;
   15233           0 :         case DEFACLOBJ_TYPE:
   15234           0 :             type = "TYPES";
   15235           0 :             break;
   15236           0 :         case DEFACLOBJ_NAMESPACE:
   15237           0 :             type = "SCHEMAS";
   15238           0 :             break;
   15239           0 :         default:
   15240             :             /* shouldn't get here */
   15241           0 :             pg_fatal("unrecognized object type in default privileges: %d",
   15242             :                      (int) daclinfo->defaclobjtype);
   15243             :             type = "";            /* keep compiler quiet */
   15244             :     }
   15245             : 
   15246         252 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   15247             : 
   15248             :     /* build the actual command(s) for this tuple */
   15249         252 :     if (!buildDefaultACLCommands(type,
   15250         252 :                                  daclinfo->dobj.namespace != NULL ?
   15251         128 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   15252         252 :                                  daclinfo->dacl.acl,
   15253         252 :                                  daclinfo->dacl.acldefault,
   15254             :                                  daclinfo->defaclrole,
   15255             :                                  fout->remoteVersion,
   15256             :                                  q))
   15257           0 :         pg_fatal("could not parse default ACL list (%s)",
   15258             :                  daclinfo->dacl.acl);
   15259             : 
   15260         252 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15261         252 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   15262         252 :                      ARCHIVE_OPTS(.tag = tag->data,
   15263             :                                   .namespace = daclinfo->dobj.namespace ?
   15264             :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   15265             :                                   .owner = daclinfo->defaclrole,
   15266             :                                   .description = "DEFAULT ACL",
   15267             :                                   .section = SECTION_POST_DATA,
   15268             :                                   .createStmt = q->data));
   15269             : 
   15270         252 :     destroyPQExpBuffer(tag);
   15271         252 :     destroyPQExpBuffer(q);
   15272             : }
   15273             : 
   15274             : /*----------
   15275             :  * Write out grant/revoke information
   15276             :  *
   15277             :  * 'objDumpId' is the dump ID of the underlying object.
   15278             :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   15279             :  *      or InvalidDumpId if there is no need for a second dependency.
   15280             :  * 'type' must be one of
   15281             :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   15282             :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   15283             :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   15284             :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   15285             :  *      (Currently we assume that subname is only provided for table columns.)
   15286             :  * 'nspname' is the namespace the object is in (NULL if none).
   15287             :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   15288             :  *      to use the default for the object type.
   15289             :  * 'owner' is the owner, NULL if there is no owner (for languages).
   15290             :  * 'dacl' is the DumpableAcl struct for the object.
   15291             :  *
   15292             :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   15293             :  * no ACL entry was created.
   15294             :  *----------
   15295             :  */
   15296             : static DumpId
   15297       45174 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   15298             :         const char *type, const char *name, const char *subname,
   15299             :         const char *nspname, const char *tag, const char *owner,
   15300             :         const DumpableAcl *dacl)
   15301             : {
   15302       45174 :     DumpId      aclDumpId = InvalidDumpId;
   15303       45174 :     DumpOptions *dopt = fout->dopt;
   15304       45174 :     const char *acls = dacl->acl;
   15305       45174 :     const char *acldefault = dacl->acldefault;
   15306       45174 :     char        privtype = dacl->privtype;
   15307       45174 :     const char *initprivs = dacl->initprivs;
   15308             :     const char *baseacls;
   15309             :     PQExpBuffer sql;
   15310             : 
   15311             :     /* Do nothing if ACL dump is not enabled */
   15312       45174 :     if (dopt->aclsSkip)
   15313         636 :         return InvalidDumpId;
   15314             : 
   15315             :     /* --data-only skips ACLs *except* large object ACLs */
   15316       44538 :     if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
   15317           0 :         return InvalidDumpId;
   15318             : 
   15319       44538 :     sql = createPQExpBuffer();
   15320             : 
   15321             :     /*
   15322             :      * In binary upgrade mode, we don't run an extension's script but instead
   15323             :      * dump out the objects independently and then recreate them.  To preserve
   15324             :      * any initial privileges which were set on extension objects, we need to
   15325             :      * compute the set of GRANT and REVOKE commands necessary to get from the
   15326             :      * default privileges of an object to its initial privileges as recorded
   15327             :      * in pg_init_privs.
   15328             :      *
   15329             :      * At restore time, we apply these commands after having called
   15330             :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   15331             :      * copy the results into pg_init_privs.  This is how we preserve the
   15332             :      * contents of that catalog across binary upgrades.
   15333             :      */
   15334       44538 :     if (dopt->binary_upgrade && privtype == 'e' &&
   15335          26 :         initprivs && *initprivs != '\0')
   15336             :     {
   15337          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   15338          26 :         if (!buildACLCommands(name, subname, nspname, type,
   15339             :                               initprivs, acldefault, owner,
   15340             :                               "", fout->remoteVersion, sql))
   15341           0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15342             :                      initprivs, acldefault, name, type);
   15343          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   15344             :     }
   15345             : 
   15346             :     /*
   15347             :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   15348             :      * actual current ACL, starting from the initprivs if given, else from the
   15349             :      * object-type-specific default.  Also, while buildACLCommands will assume
   15350             :      * that a NULL/empty acls string means it needn't do anything, what that
   15351             :      * actually represents is the object-type-specific default; so we need to
   15352             :      * substitute the acldefault string to get the right results in that case.
   15353             :      */
   15354       44538 :     if (initprivs && *initprivs != '\0')
   15355             :     {
   15356       41070 :         baseacls = initprivs;
   15357       41070 :         if (acls == NULL || *acls == '\0')
   15358          34 :             acls = acldefault;
   15359             :     }
   15360             :     else
   15361        3468 :         baseacls = acldefault;
   15362             : 
   15363       44538 :     if (!buildACLCommands(name, subname, nspname, type,
   15364             :                           acls, baseacls, owner,
   15365             :                           "", fout->remoteVersion, sql))
   15366           0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15367             :                  acls, baseacls, name, type);
   15368             : 
   15369       44538 :     if (sql->len > 0)
   15370             :     {
   15371        3636 :         PQExpBuffer tagbuf = createPQExpBuffer();
   15372             :         DumpId      aclDeps[2];
   15373        3636 :         int         nDeps = 0;
   15374             : 
   15375        3636 :         if (tag)
   15376           0 :             appendPQExpBufferStr(tagbuf, tag);
   15377        3636 :         else if (subname)
   15378        2146 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   15379             :         else
   15380        1490 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   15381             : 
   15382        3636 :         aclDeps[nDeps++] = objDumpId;
   15383        3636 :         if (altDumpId != InvalidDumpId)
   15384        1998 :             aclDeps[nDeps++] = altDumpId;
   15385             : 
   15386        3636 :         aclDumpId = createDumpId();
   15387             : 
   15388        3636 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   15389        3636 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   15390             :                                   .namespace = nspname,
   15391             :                                   .owner = owner,
   15392             :                                   .description = "ACL",
   15393             :                                   .section = SECTION_NONE,
   15394             :                                   .createStmt = sql->data,
   15395             :                                   .deps = aclDeps,
   15396             :                                   .nDeps = nDeps));
   15397             : 
   15398        3636 :         destroyPQExpBuffer(tagbuf);
   15399             :     }
   15400             : 
   15401       44538 :     destroyPQExpBuffer(sql);
   15402             : 
   15403       44538 :     return aclDumpId;
   15404             : }
   15405             : 
   15406             : /*
   15407             :  * dumpSecLabel
   15408             :  *
   15409             :  * This routine is used to dump any security labels associated with the
   15410             :  * object handed to this routine. The routine takes the object type
   15411             :  * and object name (ready to print, except for schema decoration), plus
   15412             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   15413             :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   15414             :  * plus the dump ID for the object (for setting a dependency).
   15415             :  * If a matching pg_seclabel entry is found, it is dumped.
   15416             :  *
   15417             :  * Note: although this routine takes a dumpId for dependency purposes,
   15418             :  * that purpose is just to mark the dependency in the emitted dump file
   15419             :  * for possible future use by pg_restore.  We do NOT use it for determining
   15420             :  * ordering of the label in the dump file, because this routine is called
   15421             :  * after dependency sorting occurs.  This routine should be called just after
   15422             :  * calling ArchiveEntry() for the specified object.
   15423             :  */
   15424             : static void
   15425           0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   15426             :              const char *namespace, const char *owner,
   15427             :              CatalogId catalogId, int subid, DumpId dumpId)
   15428             : {
   15429           0 :     DumpOptions *dopt = fout->dopt;
   15430             :     SecLabelItem *labels;
   15431             :     int         nlabels;
   15432             :     int         i;
   15433             :     PQExpBuffer query;
   15434             : 
   15435             :     /* do nothing, if --no-security-labels is supplied */
   15436           0 :     if (dopt->no_security_labels)
   15437           0 :         return;
   15438             : 
   15439             :     /*
   15440             :      * Security labels are schema not data ... except large object labels are
   15441             :      * data
   15442             :      */
   15443           0 :     if (strcmp(type, "LARGE OBJECT") != 0)
   15444             :     {
   15445           0 :         if (dopt->dataOnly)
   15446           0 :             return;
   15447             :     }
   15448             :     else
   15449             :     {
   15450             :         /* We do dump large object security labels in binary-upgrade mode */
   15451           0 :         if (dopt->schemaOnly && !dopt->binary_upgrade)
   15452           0 :             return;
   15453             :     }
   15454             : 
   15455             :     /* Search for security labels associated with catalogId, using table */
   15456           0 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   15457             : 
   15458           0 :     query = createPQExpBuffer();
   15459             : 
   15460           0 :     for (i = 0; i < nlabels; i++)
   15461             :     {
   15462             :         /*
   15463             :          * Ignore label entries for which the subid doesn't match.
   15464             :          */
   15465           0 :         if (labels[i].objsubid != subid)
   15466           0 :             continue;
   15467             : 
   15468           0 :         appendPQExpBuffer(query,
   15469             :                           "SECURITY LABEL FOR %s ON %s ",
   15470           0 :                           fmtId(labels[i].provider), type);
   15471           0 :         if (namespace && *namespace)
   15472           0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   15473           0 :         appendPQExpBuffer(query, "%s IS ", name);
   15474           0 :         appendStringLiteralAH(query, labels[i].label, fout);
   15475           0 :         appendPQExpBufferStr(query, ";\n");
   15476             :     }
   15477             : 
   15478           0 :     if (query->len > 0)
   15479             :     {
   15480           0 :         PQExpBuffer tag = createPQExpBuffer();
   15481             : 
   15482           0 :         appendPQExpBuffer(tag, "%s %s", type, name);
   15483           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15484           0 :                      ARCHIVE_OPTS(.tag = tag->data,
   15485             :                                   .namespace = namespace,
   15486             :                                   .owner = owner,
   15487             :                                   .description = "SECURITY LABEL",
   15488             :                                   .section = SECTION_NONE,
   15489             :                                   .createStmt = query->data,
   15490             :                                   .deps = &dumpId,
   15491             :                                   .nDeps = 1));
   15492           0 :         destroyPQExpBuffer(tag);
   15493             :     }
   15494             : 
   15495           0 :     destroyPQExpBuffer(query);
   15496             : }
   15497             : 
   15498             : /*
   15499             :  * dumpTableSecLabel
   15500             :  *
   15501             :  * As above, but dump security label for both the specified table (or view)
   15502             :  * and its columns.
   15503             :  */
   15504             : static void
   15505           0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   15506             : {
   15507           0 :     DumpOptions *dopt = fout->dopt;
   15508             :     SecLabelItem *labels;
   15509             :     int         nlabels;
   15510             :     int         i;
   15511             :     PQExpBuffer query;
   15512             :     PQExpBuffer target;
   15513             : 
   15514             :     /* do nothing, if --no-security-labels is supplied */
   15515           0 :     if (dopt->no_security_labels)
   15516           0 :         return;
   15517             : 
   15518             :     /* SecLabel are SCHEMA not data */
   15519           0 :     if (dopt->dataOnly)
   15520           0 :         return;
   15521             : 
   15522             :     /* Search for comments associated with relation, using table */
   15523           0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   15524             :                             tbinfo->dobj.catId.oid,
   15525             :                             &labels);
   15526             : 
   15527             :     /* If security labels exist, build SECURITY LABEL statements */
   15528           0 :     if (nlabels <= 0)
   15529           0 :         return;
   15530             : 
   15531           0 :     query = createPQExpBuffer();
   15532           0 :     target = createPQExpBuffer();
   15533             : 
   15534           0 :     for (i = 0; i < nlabels; i++)
   15535             :     {
   15536             :         const char *colname;
   15537           0 :         const char *provider = labels[i].provider;
   15538           0 :         const char *label = labels[i].label;
   15539           0 :         int         objsubid = labels[i].objsubid;
   15540             : 
   15541           0 :         resetPQExpBuffer(target);
   15542           0 :         if (objsubid == 0)
   15543             :         {
   15544           0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   15545           0 :                               fmtQualifiedDumpable(tbinfo));
   15546             :         }
   15547             :         else
   15548             :         {
   15549           0 :             colname = getAttrName(objsubid, tbinfo);
   15550             :             /* first fmtXXX result must be consumed before calling again */
   15551           0 :             appendPQExpBuffer(target, "COLUMN %s",
   15552           0 :                               fmtQualifiedDumpable(tbinfo));
   15553           0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   15554             :         }
   15555           0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   15556             :                           fmtId(provider), target->data);
   15557           0 :         appendStringLiteralAH(query, label, fout);
   15558           0 :         appendPQExpBufferStr(query, ";\n");
   15559             :     }
   15560           0 :     if (query->len > 0)
   15561             :     {
   15562           0 :         resetPQExpBuffer(target);
   15563           0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   15564           0 :                           fmtId(tbinfo->dobj.name));
   15565           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15566           0 :                      ARCHIVE_OPTS(.tag = target->data,
   15567             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   15568             :                                   .owner = tbinfo->rolname,
   15569             :                                   .description = "SECURITY LABEL",
   15570             :                                   .section = SECTION_NONE,
   15571             :                                   .createStmt = query->data,
   15572             :                                   .deps = &(tbinfo->dobj.dumpId),
   15573             :                                   .nDeps = 1));
   15574             :     }
   15575           0 :     destroyPQExpBuffer(query);
   15576           0 :     destroyPQExpBuffer(target);
   15577             : }
   15578             : 
   15579             : /*
   15580             :  * findSecLabels
   15581             :  *
   15582             :  * Find the security label(s), if any, associated with the given object.
   15583             :  * All the objsubid values associated with the given classoid/objoid are
   15584             :  * found with one search.
   15585             :  */
   15586             : static int
   15587           0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   15588             : {
   15589           0 :     SecLabelItem *middle = NULL;
   15590             :     SecLabelItem *low;
   15591             :     SecLabelItem *high;
   15592             :     int         nmatch;
   15593             : 
   15594           0 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   15595             :     {
   15596           0 :         *items = NULL;
   15597           0 :         return 0;
   15598             :     }
   15599             : 
   15600             :     /*
   15601             :      * Do binary search to find some item matching the object.
   15602             :      */
   15603           0 :     low = &seclabels[0];
   15604           0 :     high = &seclabels[nseclabels - 1];
   15605           0 :     while (low <= high)
   15606             :     {
   15607           0 :         middle = low + (high - low) / 2;
   15608             : 
   15609           0 :         if (classoid < middle->classoid)
   15610           0 :             high = middle - 1;
   15611           0 :         else if (classoid > middle->classoid)
   15612           0 :             low = middle + 1;
   15613           0 :         else if (objoid < middle->objoid)
   15614           0 :             high = middle - 1;
   15615           0 :         else if (objoid > middle->objoid)
   15616           0 :             low = middle + 1;
   15617             :         else
   15618           0 :             break;              /* found a match */
   15619             :     }
   15620             : 
   15621           0 :     if (low > high)              /* no matches */
   15622             :     {
   15623           0 :         *items = NULL;
   15624           0 :         return 0;
   15625             :     }
   15626             : 
   15627             :     /*
   15628             :      * Now determine how many items match the object.  The search loop
   15629             :      * invariant still holds: only items between low and high inclusive could
   15630             :      * match.
   15631             :      */
   15632           0 :     nmatch = 1;
   15633           0 :     while (middle > low)
   15634             :     {
   15635           0 :         if (classoid != middle[-1].classoid ||
   15636           0 :             objoid != middle[-1].objoid)
   15637             :             break;
   15638           0 :         middle--;
   15639           0 :         nmatch++;
   15640             :     }
   15641             : 
   15642           0 :     *items = middle;
   15643             : 
   15644           0 :     middle += nmatch;
   15645           0 :     while (middle <= high)
   15646             :     {
   15647           0 :         if (classoid != middle->classoid ||
   15648           0 :             objoid != middle->objoid)
   15649             :             break;
   15650           0 :         middle++;
   15651           0 :         nmatch++;
   15652             :     }
   15653             : 
   15654           0 :     return nmatch;
   15655             : }
   15656             : 
   15657             : /*
   15658             :  * collectSecLabels
   15659             :  *
   15660             :  * Construct a table of all security labels available for database objects;
   15661             :  * also set the has-seclabel component flag for each relevant object.
   15662             :  *
   15663             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   15664             :  */
   15665             : static void
   15666         304 : collectSecLabels(Archive *fout)
   15667             : {
   15668             :     PGresult   *res;
   15669             :     PQExpBuffer query;
   15670             :     int         i_label;
   15671             :     int         i_provider;
   15672             :     int         i_classoid;
   15673             :     int         i_objoid;
   15674             :     int         i_objsubid;
   15675             :     int         ntups;
   15676             :     int         i;
   15677             :     DumpableObject *dobj;
   15678             : 
   15679         304 :     query = createPQExpBuffer();
   15680             : 
   15681         304 :     appendPQExpBufferStr(query,
   15682             :                          "SELECT label, provider, classoid, objoid, objsubid "
   15683             :                          "FROM pg_catalog.pg_seclabel "
   15684             :                          "ORDER BY classoid, objoid, objsubid");
   15685             : 
   15686         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15687             : 
   15688             :     /* Construct lookup table containing OIDs in numeric form */
   15689         304 :     i_label = PQfnumber(res, "label");
   15690         304 :     i_provider = PQfnumber(res, "provider");
   15691         304 :     i_classoid = PQfnumber(res, "classoid");
   15692         304 :     i_objoid = PQfnumber(res, "objoid");
   15693         304 :     i_objsubid = PQfnumber(res, "objsubid");
   15694             : 
   15695         304 :     ntups = PQntuples(res);
   15696             : 
   15697         304 :     seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
   15698         304 :     nseclabels = 0;
   15699         304 :     dobj = NULL;
   15700             : 
   15701         304 :     for (i = 0; i < ntups; i++)
   15702             :     {
   15703             :         CatalogId   objId;
   15704             :         int         subid;
   15705             : 
   15706           0 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   15707           0 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   15708           0 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   15709             : 
   15710             :         /* We needn't remember labels that don't match any dumpable object */
   15711           0 :         if (dobj == NULL ||
   15712           0 :             dobj->catId.tableoid != objId.tableoid ||
   15713           0 :             dobj->catId.oid != objId.oid)
   15714           0 :             dobj = findObjectByCatalogId(objId);
   15715           0 :         if (dobj == NULL)
   15716           0 :             continue;
   15717             : 
   15718             :         /*
   15719             :          * Labels on columns of composite types are linked to the type's
   15720             :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   15721             :          * in the type's own DumpableObject.
   15722             :          */
   15723           0 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   15724           0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   15725           0 :         {
   15726             :             TypeInfo   *cTypeInfo;
   15727             : 
   15728           0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   15729           0 :             if (cTypeInfo)
   15730           0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   15731             :         }
   15732             :         else
   15733           0 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   15734             : 
   15735           0 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   15736           0 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   15737           0 :         seclabels[nseclabels].classoid = objId.tableoid;
   15738           0 :         seclabels[nseclabels].objoid = objId.oid;
   15739           0 :         seclabels[nseclabels].objsubid = subid;
   15740           0 :         nseclabels++;
   15741             :     }
   15742             : 
   15743         304 :     PQclear(res);
   15744         304 :     destroyPQExpBuffer(query);
   15745         304 : }
   15746             : 
   15747             : /*
   15748             :  * dumpTable
   15749             :  *    write out to fout the declarations (not data) of a user-defined table
   15750             :  */
   15751             : static void
   15752       49336 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   15753             : {
   15754       49336 :     DumpOptions *dopt = fout->dopt;
   15755       49336 :     DumpId      tableAclDumpId = InvalidDumpId;
   15756             :     char       *namecopy;
   15757             : 
   15758             :     /* Do nothing in data-only dump */
   15759       49336 :     if (dopt->dataOnly)
   15760        1734 :         return;
   15761             : 
   15762       47602 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15763             :     {
   15764       11228 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   15765         686 :             dumpSequence(fout, tbinfo);
   15766             :         else
   15767       10542 :             dumpTableSchema(fout, tbinfo);
   15768             :     }
   15769             : 
   15770             :     /* Handle the ACL here */
   15771       47602 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   15772       47602 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15773             :     {
   15774       37238 :         const char *objtype =
   15775       37238 :             (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   15776             : 
   15777             :         tableAclDumpId =
   15778       37238 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   15779             :                     objtype, namecopy, NULL,
   15780       37238 :                     tbinfo->dobj.namespace->dobj.name,
   15781             :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   15782             :     }
   15783             : 
   15784             :     /*
   15785             :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   15786             :      * rather than trying to fetch them during getTableAttrs, so that we won't
   15787             :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   15788             :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   15789             :      */
   15790       47602 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   15791             :     {
   15792         498 :         PQExpBuffer query = createPQExpBuffer();
   15793             :         PGresult   *res;
   15794             :         int         i;
   15795             : 
   15796         498 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   15797             :         {
   15798             :             /* Set up query for column ACLs */
   15799         258 :             appendPQExpBufferStr(query,
   15800             :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   15801             : 
   15802         258 :             if (fout->remoteVersion >= 90600)
   15803             :             {
   15804             :                 /*
   15805             :                  * In principle we should call acldefault('c', relowner) to
   15806             :                  * get the default ACL for a column.  However, we don't
   15807             :                  * currently store the numeric OID of the relowner in
   15808             :                  * TableInfo.  We could convert the owner name using regrole,
   15809             :                  * but that creates a risk of failure due to concurrent role
   15810             :                  * renames.  Given that the default ACL for columns is empty
   15811             :                  * and is likely to stay that way, it's not worth extra cycles
   15812             :                  * and risk to avoid hard-wiring that knowledge here.
   15813             :                  */
   15814         258 :                 appendPQExpBufferStr(query,
   15815             :                                      "SELECT at.attname, "
   15816             :                                      "at.attacl, "
   15817             :                                      "'{}' AS acldefault, "
   15818             :                                      "pip.privtype, pip.initprivs "
   15819             :                                      "FROM pg_catalog.pg_attribute at "
   15820             :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   15821             :                                      "(at.attrelid = pip.objoid "
   15822             :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   15823             :                                      "AND at.attnum = pip.objsubid) "
   15824             :                                      "WHERE at.attrelid = $1 AND "
   15825             :                                      "NOT at.attisdropped "
   15826             :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   15827             :                                      "ORDER BY at.attnum");
   15828             :             }
   15829             :             else
   15830             :             {
   15831           0 :                 appendPQExpBufferStr(query,
   15832             :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   15833             :                                      "NULL AS privtype, NULL AS initprivs "
   15834             :                                      "FROM pg_catalog.pg_attribute "
   15835             :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   15836             :                                      "AND attacl IS NOT NULL "
   15837             :                                      "ORDER BY attnum");
   15838             :             }
   15839             : 
   15840         258 :             ExecuteSqlStatement(fout, query->data);
   15841             : 
   15842         258 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   15843             :         }
   15844             : 
   15845         498 :         printfPQExpBuffer(query,
   15846             :                           "EXECUTE getColumnACLs('%u')",
   15847             :                           tbinfo->dobj.catId.oid);
   15848             : 
   15849         498 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15850             : 
   15851        6928 :         for (i = 0; i < PQntuples(res); i++)
   15852             :         {
   15853        6430 :             char       *attname = PQgetvalue(res, i, 0);
   15854        6430 :             char       *attacl = PQgetvalue(res, i, 1);
   15855        6430 :             char       *acldefault = PQgetvalue(res, i, 2);
   15856        6430 :             char        privtype = *(PQgetvalue(res, i, 3));
   15857        6430 :             char       *initprivs = PQgetvalue(res, i, 4);
   15858             :             DumpableAcl coldacl;
   15859             :             char       *attnamecopy;
   15860             : 
   15861        6430 :             coldacl.acl = attacl;
   15862        6430 :             coldacl.acldefault = acldefault;
   15863        6430 :             coldacl.privtype = privtype;
   15864        6430 :             coldacl.initprivs = initprivs;
   15865        6430 :             attnamecopy = pg_strdup(fmtId(attname));
   15866             : 
   15867             :             /*
   15868             :              * Column's GRANT type is always TABLE.  Each column ACL depends
   15869             :              * on the table-level ACL, since we can restore column ACLs in
   15870             :              * parallel but the table-level ACL has to be done first.
   15871             :              */
   15872        6430 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   15873             :                     "TABLE", namecopy, attnamecopy,
   15874        6430 :                     tbinfo->dobj.namespace->dobj.name,
   15875             :                     NULL, tbinfo->rolname, &coldacl);
   15876        6430 :             free(attnamecopy);
   15877             :         }
   15878         498 :         PQclear(res);
   15879         498 :         destroyPQExpBuffer(query);
   15880             :     }
   15881             : 
   15882       47602 :     free(namecopy);
   15883             : }
   15884             : 
   15885             : /*
   15886             :  * Create the AS clause for a view or materialized view. The semicolon is
   15887             :  * stripped because a materialized view must add a WITH NO DATA clause.
   15888             :  *
   15889             :  * This returns a new buffer which must be freed by the caller.
   15890             :  */
   15891             : static PQExpBuffer
   15892        1366 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   15893             : {
   15894        1366 :     PQExpBuffer query = createPQExpBuffer();
   15895        1366 :     PQExpBuffer result = createPQExpBuffer();
   15896             :     PGresult   *res;
   15897             :     int         len;
   15898             : 
   15899             :     /* Fetch the view definition */
   15900        1366 :     appendPQExpBuffer(query,
   15901             :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   15902             :                       tbinfo->dobj.catId.oid);
   15903             : 
   15904        1366 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15905             : 
   15906        1366 :     if (PQntuples(res) != 1)
   15907             :     {
   15908           0 :         if (PQntuples(res) < 1)
   15909           0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   15910             :                      tbinfo->dobj.name);
   15911             :         else
   15912           0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   15913             :                      tbinfo->dobj.name);
   15914             :     }
   15915             : 
   15916        1366 :     len = PQgetlength(res, 0, 0);
   15917             : 
   15918        1366 :     if (len == 0)
   15919           0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   15920             :                  tbinfo->dobj.name);
   15921             : 
   15922             :     /* Strip off the trailing semicolon so that other things may follow. */
   15923             :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   15924        1366 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   15925             : 
   15926        1366 :     PQclear(res);
   15927        1366 :     destroyPQExpBuffer(query);
   15928             : 
   15929        1366 :     return result;
   15930             : }
   15931             : 
   15932             : /*
   15933             :  * Create a dummy AS clause for a view.  This is used when the real view
   15934             :  * definition has to be postponed because of circular dependencies.
   15935             :  * We must duplicate the view's external properties -- column names and types
   15936             :  * (including collation) -- so that it works for subsequent references.
   15937             :  *
   15938             :  * This returns a new buffer which must be freed by the caller.
   15939             :  */
   15940             : static PQExpBuffer
   15941          40 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   15942             : {
   15943          40 :     PQExpBuffer result = createPQExpBuffer();
   15944             :     int         j;
   15945             : 
   15946          40 :     appendPQExpBufferStr(result, "SELECT");
   15947             : 
   15948          80 :     for (j = 0; j < tbinfo->numatts; j++)
   15949             :     {
   15950          40 :         if (j > 0)
   15951          20 :             appendPQExpBufferChar(result, ',');
   15952          40 :         appendPQExpBufferStr(result, "\n    ");
   15953             : 
   15954          40 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   15955             : 
   15956             :         /*
   15957             :          * Must add collation if not default for the type, because CREATE OR
   15958             :          * REPLACE VIEW won't change it
   15959             :          */
   15960          40 :         if (OidIsValid(tbinfo->attcollation[j]))
   15961             :         {
   15962             :             CollInfo   *coll;
   15963             : 
   15964           0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   15965           0 :             if (coll)
   15966           0 :                 appendPQExpBuffer(result, " COLLATE %s",
   15967           0 :                                   fmtQualifiedDumpable(coll));
   15968             :         }
   15969             : 
   15970          40 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   15971             :     }
   15972             : 
   15973          40 :     return result;
   15974             : }
   15975             : 
   15976             : /*
   15977             :  * dumpTableSchema
   15978             :  *    write the declaration (not data) of one user-defined table or view
   15979             :  */
   15980             : static void
   15981       10542 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   15982             : {
   15983       10542 :     DumpOptions *dopt = fout->dopt;
   15984       10542 :     PQExpBuffer q = createPQExpBuffer();
   15985       10542 :     PQExpBuffer delq = createPQExpBuffer();
   15986             :     char       *qrelname;
   15987             :     char       *qualrelname;
   15988             :     int         numParents;
   15989             :     TableInfo **parents;
   15990             :     int         actual_atts;    /* number of attrs in this CREATE statement */
   15991             :     const char *reltypename;
   15992             :     char       *storage;
   15993             :     int         j,
   15994             :                 k;
   15995             : 
   15996             :     /* We had better have loaded per-column details about this table */
   15997             :     Assert(tbinfo->interesting);
   15998             : 
   15999       10542 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   16000       10542 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   16001             : 
   16002       10542 :     if (tbinfo->hasoids)
   16003           0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   16004             :                        qrelname);
   16005             : 
   16006       10542 :     if (dopt->binary_upgrade)
   16007        1510 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   16008             : 
   16009             :     /* Is it a table or a view? */
   16010       10542 :     if (tbinfo->relkind == RELKIND_VIEW)
   16011             :     {
   16012             :         PQExpBuffer result;
   16013             : 
   16014             :         /*
   16015             :          * Note: keep this code in sync with the is_view case in dumpRule()
   16016             :          */
   16017             : 
   16018         692 :         reltypename = "VIEW";
   16019             : 
   16020         692 :         appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   16021             : 
   16022         692 :         if (dopt->binary_upgrade)
   16023          96 :             binary_upgrade_set_pg_class_oids(fout, q,
   16024             :                                              tbinfo->dobj.catId.oid, false);
   16025             : 
   16026         692 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   16027             : 
   16028         692 :         if (tbinfo->dummy_view)
   16029          20 :             result = createDummyViewAsClause(fout, tbinfo);
   16030             :         else
   16031             :         {
   16032         672 :             if (nonemptyReloptions(tbinfo->reloptions))
   16033             :             {
   16034         112 :                 appendPQExpBufferStr(q, " WITH (");
   16035         112 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   16036         112 :                 appendPQExpBufferChar(q, ')');
   16037             :             }
   16038         672 :             result = createViewAsClause(fout, tbinfo);
   16039             :         }
   16040         692 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   16041         692 :         destroyPQExpBuffer(result);
   16042             : 
   16043         692 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   16044          66 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   16045         692 :         appendPQExpBufferStr(q, ";\n");
   16046             :     }
   16047             :     else
   16048             :     {
   16049        9850 :         char       *partkeydef = NULL;
   16050        9850 :         char       *ftoptions = NULL;
   16051        9850 :         char       *srvname = NULL;
   16052        9850 :         char       *foreign = "";
   16053             : 
   16054             :         /*
   16055             :          * Set reltypename, and collect any relkind-specific data that we
   16056             :          * didn't fetch during getTables().
   16057             :          */
   16058        9850 :         switch (tbinfo->relkind)
   16059             :         {
   16060        1006 :             case RELKIND_PARTITIONED_TABLE:
   16061             :                 {
   16062        1006 :                     PQExpBuffer query = createPQExpBuffer();
   16063             :                     PGresult   *res;
   16064             : 
   16065        1006 :                     reltypename = "TABLE";
   16066             : 
   16067             :                     /* retrieve partition key definition */
   16068        1006 :                     appendPQExpBuffer(query,
   16069             :                                       "SELECT pg_get_partkeydef('%u')",
   16070             :                                       tbinfo->dobj.catId.oid);
   16071        1006 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16072        1006 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   16073        1006 :                     PQclear(res);
   16074        1006 :                     destroyPQExpBuffer(query);
   16075        1006 :                     break;
   16076             :                 }
   16077          70 :             case RELKIND_FOREIGN_TABLE:
   16078             :                 {
   16079          70 :                     PQExpBuffer query = createPQExpBuffer();
   16080             :                     PGresult   *res;
   16081             :                     int         i_srvname;
   16082             :                     int         i_ftoptions;
   16083             : 
   16084          70 :                     reltypename = "FOREIGN TABLE";
   16085             : 
   16086             :                     /* retrieve name of foreign server and generic options */
   16087          70 :                     appendPQExpBuffer(query,
   16088             :                                       "SELECT fs.srvname, "
   16089             :                                       "pg_catalog.array_to_string(ARRAY("
   16090             :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   16091             :                                       "' ' || pg_catalog.quote_literal(option_value) "
   16092             :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   16093             :                                       "ORDER BY option_name"
   16094             :                                       "), E',\n    ') AS ftoptions "
   16095             :                                       "FROM pg_catalog.pg_foreign_table ft "
   16096             :                                       "JOIN pg_catalog.pg_foreign_server fs "
   16097             :                                       "ON (fs.oid = ft.ftserver) "
   16098             :                                       "WHERE ft.ftrelid = '%u'",
   16099             :                                       tbinfo->dobj.catId.oid);
   16100          70 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16101          70 :                     i_srvname = PQfnumber(res, "srvname");
   16102          70 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   16103          70 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   16104          70 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   16105          70 :                     PQclear(res);
   16106          70 :                     destroyPQExpBuffer(query);
   16107             : 
   16108          70 :                     foreign = "FOREIGN ";
   16109          70 :                     break;
   16110             :                 }
   16111         674 :             case RELKIND_MATVIEW:
   16112         674 :                 reltypename = "MATERIALIZED VIEW";
   16113         674 :                 break;
   16114        8100 :             default:
   16115        8100 :                 reltypename = "TABLE";
   16116        8100 :                 break;
   16117             :         }
   16118             : 
   16119        9850 :         numParents = tbinfo->numParents;
   16120        9850 :         parents = tbinfo->parents;
   16121             : 
   16122        9850 :         appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   16123             : 
   16124        9850 :         if (dopt->binary_upgrade)
   16125        1414 :             binary_upgrade_set_pg_class_oids(fout, q,
   16126             :                                              tbinfo->dobj.catId.oid, false);
   16127             : 
   16128        9850 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   16129        9850 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   16130             :                           "UNLOGGED " : "",
   16131             :                           reltypename,
   16132             :                           qualrelname);
   16133             : 
   16134             :         /*
   16135             :          * Attach to type, if reloftype; except in case of a binary upgrade,
   16136             :          * we dump the table normally and attach it to the type afterward.
   16137             :          */
   16138        9850 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   16139          48 :             appendPQExpBuffer(q, " OF %s",
   16140             :                               getFormattedTypeName(fout, tbinfo->reloftype,
   16141             :                                                    zeroIsError));
   16142             : 
   16143        9850 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   16144             :         {
   16145             :             /* Dump the attributes */
   16146        9176 :             actual_atts = 0;
   16147       44028 :             for (j = 0; j < tbinfo->numatts; j++)
   16148             :             {
   16149             :                 /*
   16150             :                  * Normally, dump if it's locally defined in this table, and
   16151             :                  * not dropped.  But for binary upgrade, we'll dump all the
   16152             :                  * columns, and then fix up the dropped and nonlocal cases
   16153             :                  * below.
   16154             :                  */
   16155       34852 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   16156             :                 {
   16157             :                     bool        print_default;
   16158             :                     bool        print_notnull;
   16159             : 
   16160             :                     /*
   16161             :                      * Default value --- suppress if to be printed separately
   16162             :                      * or not at all.
   16163             :                      */
   16164       67970 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   16165       34668 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   16166        1446 :                                      !tbinfo->attrdefs[j]->separate);
   16167             : 
   16168             :                     /*
   16169             :                      * Not Null constraint --- suppress unless it is locally
   16170             :                      * defined, except if partition, or in binary-upgrade case
   16171             :                      * where that won't work.
   16172             :                      */
   16173       33222 :                     print_notnull =
   16174       37520 :                         (tbinfo->notnull_constrs[j] != NULL &&
   16175        4298 :                          (!tbinfo->notnull_inh[j] || tbinfo->ispartition ||
   16176          96 :                           dopt->binary_upgrade));
   16177             : 
   16178             :                     /*
   16179             :                      * Skip column if fully defined by reloftype, except in
   16180             :                      * binary upgrade
   16181             :                      */
   16182       33222 :                     if (OidIsValid(tbinfo->reloftype) &&
   16183         100 :                         !print_default && !print_notnull &&
   16184          60 :                         !dopt->binary_upgrade)
   16185          48 :                         continue;
   16186             : 
   16187             :                     /* Format properly if not first attr */
   16188       33174 :                     if (actual_atts == 0)
   16189        8682 :                         appendPQExpBufferStr(q, " (");
   16190             :                     else
   16191       24492 :                         appendPQExpBufferChar(q, ',');
   16192       33174 :                     appendPQExpBufferStr(q, "\n    ");
   16193       33174 :                     actual_atts++;
   16194             : 
   16195             :                     /* Attribute name */
   16196       33174 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   16197             : 
   16198       33174 :                     if (tbinfo->attisdropped[j])
   16199             :                     {
   16200             :                         /*
   16201             :                          * ALTER TABLE DROP COLUMN clears
   16202             :                          * pg_attribute.atttypid, so we will not have gotten a
   16203             :                          * valid type name; insert INTEGER as a stopgap. We'll
   16204             :                          * clean things up later.
   16205             :                          */
   16206         160 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   16207             :                         /* and skip to the next column */
   16208         160 :                         continue;
   16209             :                     }
   16210             : 
   16211             :                     /*
   16212             :                      * Attribute type; print it except when creating a typed
   16213             :                      * table ('OF type_name'), but in binary-upgrade mode,
   16214             :                      * print it in that case too.
   16215             :                      */
   16216       33014 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   16217             :                     {
   16218       32982 :                         appendPQExpBuffer(q, " %s",
   16219       32982 :                                           tbinfo->atttypnames[j]);
   16220             :                     }
   16221             : 
   16222       33014 :                     if (print_default)
   16223             :                     {
   16224        1232 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   16225         530 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   16226         530 :                                               tbinfo->attrdefs[j]->adef_expr);
   16227             :                         else
   16228         702 :                             appendPQExpBuffer(q, " DEFAULT %s",
   16229         702 :                                               tbinfo->attrdefs[j]->adef_expr);
   16230             :                     }
   16231             : 
   16232             : 
   16233       33014 :                     if (print_notnull)
   16234             :                     {
   16235        4234 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   16236        1990 :                             appendPQExpBufferStr(q, " NOT NULL");
   16237             :                         else
   16238        2244 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   16239        2244 :                                               fmtId(tbinfo->notnull_constrs[j]));
   16240             : 
   16241        4234 :                         if (tbinfo->notnull_noinh[j])
   16242        1438 :                             appendPQExpBufferStr(q, " NO INHERIT");
   16243             :                     }
   16244             : 
   16245             :                     /* Add collation if not default for the type */
   16246       33014 :                     if (OidIsValid(tbinfo->attcollation[j]))
   16247             :                     {
   16248             :                         CollInfo   *coll;
   16249             : 
   16250         138 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   16251         138 :                         if (coll)
   16252         138 :                             appendPQExpBuffer(q, " COLLATE %s",
   16253         138 :                                               fmtQualifiedDumpable(coll));
   16254             :                     }
   16255             :                 }
   16256             :             }
   16257             : 
   16258             :             /*
   16259             :              * Add non-inherited CHECK constraints, if any.
   16260             :              *
   16261             :              * For partitions, we need to include check constraints even if
   16262             :              * they're not defined locally, because the ALTER TABLE ATTACH
   16263             :              * PARTITION that we'll emit later expects the constraint to be
   16264             :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   16265             :              */
   16266       10232 :             for (j = 0; j < tbinfo->ncheck; j++)
   16267             :             {
   16268        1056 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   16269             : 
   16270        1056 :                 if (constr->separate ||
   16271         976 :                     (!constr->conislocal && !tbinfo->ispartition))
   16272         156 :                     continue;
   16273             : 
   16274         900 :                 if (actual_atts == 0)
   16275          32 :                     appendPQExpBufferStr(q, " (\n    ");
   16276             :                 else
   16277         868 :                     appendPQExpBufferStr(q, ",\n    ");
   16278             : 
   16279         900 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   16280         900 :                                   fmtId(constr->dobj.name));
   16281         900 :                 appendPQExpBufferStr(q, constr->condef);
   16282             : 
   16283         900 :                 actual_atts++;
   16284             :             }
   16285             : 
   16286        9176 :             if (actual_atts)
   16287        8714 :                 appendPQExpBufferStr(q, "\n)");
   16288         462 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   16289             :             {
   16290             :                 /*
   16291             :                  * No attributes? we must have a parenthesized attribute list,
   16292             :                  * even though empty, when not using the OF TYPE syntax.
   16293             :                  */
   16294         438 :                 appendPQExpBufferStr(q, " (\n)");
   16295             :             }
   16296             : 
   16297             :             /*
   16298             :              * Emit the INHERITS clause (not for partitions), except in
   16299             :              * binary-upgrade mode.
   16300             :              */
   16301        9176 :             if (numParents > 0 && !tbinfo->ispartition &&
   16302         702 :                 !dopt->binary_upgrade)
   16303             :             {
   16304         598 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   16305        1260 :                 for (k = 0; k < numParents; k++)
   16306             :                 {
   16307         662 :                     TableInfo  *parentRel = parents[k];
   16308             : 
   16309         662 :                     if (k > 0)
   16310          64 :                         appendPQExpBufferStr(q, ", ");
   16311         662 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   16312             :                 }
   16313         598 :                 appendPQExpBufferChar(q, ')');
   16314             :             }
   16315             : 
   16316        9176 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   16317        1006 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   16318             : 
   16319        9176 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   16320          70 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   16321             :         }
   16322             : 
   16323       19414 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   16324        9564 :             nonemptyReloptions(tbinfo->toast_reloptions))
   16325             :         {
   16326         286 :             bool        addcomma = false;
   16327             : 
   16328         286 :             appendPQExpBufferStr(q, "\nWITH (");
   16329         286 :             if (nonemptyReloptions(tbinfo->reloptions))
   16330             :             {
   16331         286 :                 addcomma = true;
   16332         286 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   16333             :             }
   16334         286 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   16335             :             {
   16336          10 :                 if (addcomma)
   16337          10 :                     appendPQExpBufferStr(q, ", ");
   16338          10 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   16339             :                                         fout);
   16340             :             }
   16341         286 :             appendPQExpBufferChar(q, ')');
   16342             :         }
   16343             : 
   16344             :         /* Dump generic options if any */
   16345        9850 :         if (ftoptions && ftoptions[0])
   16346          66 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   16347             : 
   16348             :         /*
   16349             :          * For materialized views, create the AS clause just like a view. At
   16350             :          * this point, we always mark the view as not populated.
   16351             :          */
   16352        9850 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16353             :         {
   16354             :             PQExpBuffer result;
   16355             : 
   16356         674 :             result = createViewAsClause(fout, tbinfo);
   16357         674 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   16358             :                               result->data);
   16359         674 :             destroyPQExpBuffer(result);
   16360             :         }
   16361             :         else
   16362        9176 :             appendPQExpBufferStr(q, ";\n");
   16363             : 
   16364             :         /* Materialized views can depend on extensions */
   16365        9850 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16366         674 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   16367             :                                         "pg_catalog.pg_class",
   16368             :                                         "MATERIALIZED VIEW",
   16369             :                                         qualrelname);
   16370             : 
   16371             :         /*
   16372             :          * in binary upgrade mode, update the catalog with any missing values
   16373             :          * that might be present.
   16374             :          */
   16375        9850 :         if (dopt->binary_upgrade)
   16376             :         {
   16377        7286 :             for (j = 0; j < tbinfo->numatts; j++)
   16378             :             {
   16379        5872 :                 if (tbinfo->attmissingval[j][0] != '\0')
   16380             :                 {
   16381           4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   16382           4 :                     appendPQExpBufferStr(q,
   16383             :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   16384           4 :                     appendStringLiteralAH(q, qualrelname, fout);
   16385           4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   16386           4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16387           4 :                     appendPQExpBufferChar(q, ',');
   16388           4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   16389           4 :                     appendPQExpBufferStr(q, ");\n\n");
   16390             :                 }
   16391             :             }
   16392             :         }
   16393             : 
   16394             :         /*
   16395             :          * To create binary-compatible heap files, we have to ensure the same
   16396             :          * physical column order, including dropped columns, as in the
   16397             :          * original.  Therefore, we create dropped columns above and drop them
   16398             :          * here, also updating their attlen/attalign values so that the
   16399             :          * dropped column can be skipped properly.  (We do not bother with
   16400             :          * restoring the original attbyval setting.)  Also, inheritance
   16401             :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   16402             :          * using an INHERITS clause --- the latter would possibly mess up the
   16403             :          * column order.  That also means we have to take care about setting
   16404             :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   16405             :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   16406             :          *
   16407             :          * We process foreign and partitioned tables here, even though they
   16408             :          * lack heap storage, because they can participate in inheritance
   16409             :          * relationships and we want this stuff to be consistent across the
   16410             :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   16411             :          * and matviews, even though they have storage, because we don't
   16412             :          * support altering or dropping columns in them, nor can they be part
   16413             :          * of inheritance trees.
   16414             :          */
   16415        9850 :         if (dopt->binary_upgrade &&
   16416        1414 :             (tbinfo->relkind == RELKIND_RELATION ||
   16417         202 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   16418         200 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   16419             :         {
   16420        7212 :             for (j = 0; j < tbinfo->numatts; j++)
   16421             :             {
   16422        5832 :                 if (tbinfo->attisdropped[j])
   16423             :                 {
   16424         160 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
   16425         160 :                     appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
   16426             :                                       "SET attlen = %d, "
   16427             :                                       "attalign = '%c', attbyval = false\n"
   16428             :                                       "WHERE attname = ",
   16429         160 :                                       tbinfo->attlen[j],
   16430         160 :                                       tbinfo->attalign[j]);
   16431         160 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16432         160 :                     appendPQExpBufferStr(q, "\n  AND attrelid = ");
   16433         160 :                     appendStringLiteralAH(q, qualrelname, fout);
   16434         160 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   16435             : 
   16436         160 :                     if (tbinfo->relkind == RELKIND_RELATION ||
   16437          32 :                         tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   16438         160 :                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
   16439             :                                           qualrelname);
   16440             :                     else
   16441           0 :                         appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
   16442             :                                           qualrelname);
   16443         160 :                     appendPQExpBuffer(q, "DROP COLUMN %s;\n",
   16444         160 :                                       fmtId(tbinfo->attnames[j]));
   16445             :                 }
   16446        5672 :                 else if (!tbinfo->attislocal[j])
   16447             :                 {
   16448        1124 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
   16449        1124 :                     appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   16450             :                                          "SET attislocal = false\n"
   16451             :                                          "WHERE attname = ");
   16452        1124 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16453        1124 :                     appendPQExpBufferStr(q, "\n  AND attrelid = ");
   16454        1124 :                     appendStringLiteralAH(q, qualrelname, fout);
   16455        1124 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   16456             : 
   16457             :                     /*
   16458             :                      * If a not-null constraint comes from inheritance, reset
   16459             :                      * conislocal.  The inhcount is fixed later.
   16460             :                      */
   16461        1124 :                     if (tbinfo->notnull_constrs[j] != NULL &&
   16462         156 :                         !tbinfo->notnull_throwaway[j] &&
   16463         126 :                         tbinfo->notnull_inh[j] &&
   16464          96 :                         !tbinfo->ispartition)
   16465             :                     {
   16466          30 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   16467             :                                              "SET conislocal = false\n"
   16468             :                                              "WHERE contype = 'n' AND conrelid = ");
   16469          30 :                         appendStringLiteralAH(q, qualrelname, fout);
   16470          30 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   16471             :                                              "conname = ");
   16472          30 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   16473          30 :                         appendPQExpBufferStr(q, ";\n");
   16474             :                     }
   16475             :                 }
   16476             :             }
   16477             : 
   16478             :             /*
   16479             :              * Add inherited CHECK constraints, if any.
   16480             :              *
   16481             :              * For partitions, they were already dumped, and conislocal
   16482             :              * doesn't need fixing.
   16483             :              */
   16484        1482 :             for (k = 0; k < tbinfo->ncheck; k++)
   16485             :             {
   16486         102 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   16487             : 
   16488         102 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   16489          98 :                     continue;
   16490             : 
   16491           4 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
   16492           4 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   16493             :                                   foreign, qualrelname,
   16494           4 :                                   fmtId(constr->dobj.name),
   16495             :                                   constr->condef);
   16496           4 :                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   16497             :                                      "SET conislocal = false\n"
   16498             :                                      "WHERE contype = 'c' AND conname = ");
   16499           4 :                 appendStringLiteralAH(q, constr->dobj.name, fout);
   16500           4 :                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
   16501           4 :                 appendStringLiteralAH(q, qualrelname, fout);
   16502           4 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   16503             :             }
   16504             : 
   16505        1380 :             if (numParents > 0 && !tbinfo->ispartition)
   16506             :             {
   16507         104 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   16508         224 :                 for (k = 0; k < numParents; k++)
   16509             :                 {
   16510         120 :                     TableInfo  *parentRel = parents[k];
   16511             : 
   16512         120 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   16513             :                                       qualrelname,
   16514         120 :                                       fmtQualifiedDumpable(parentRel));
   16515             :                 }
   16516             :             }
   16517             : 
   16518        1380 :             if (OidIsValid(tbinfo->reloftype))
   16519             :             {
   16520          12 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   16521          12 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   16522             :                                   qualrelname,
   16523             :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   16524             :                                                        zeroIsError));
   16525             :             }
   16526             :         }
   16527             : 
   16528             :         /*
   16529             :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   16530             :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   16531             :          * TOAST tables semi-independently, here we see them only as children
   16532             :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   16533             :          * child toast table is handled below.)
   16534             :          */
   16535        9850 :         if (dopt->binary_upgrade &&
   16536        1414 :             (tbinfo->relkind == RELKIND_RELATION ||
   16537         202 :              tbinfo->relkind == RELKIND_MATVIEW))
   16538             :         {
   16539        1246 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   16540        1246 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   16541             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   16542             :                               "WHERE oid = ",
   16543             :                               tbinfo->frozenxid, tbinfo->minmxid);
   16544        1246 :             appendStringLiteralAH(q, qualrelname, fout);
   16545        1246 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   16546             : 
   16547        1246 :             if (tbinfo->toast_oid)
   16548             :             {
   16549             :                 /*
   16550             :                  * The toast table will have the same OID at restore, so we
   16551             :                  * can safely target it by OID.
   16552             :                  */
   16553         550 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   16554         550 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   16555             :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   16556             :                                   "WHERE oid = '%u';\n",
   16557             :                                   tbinfo->toast_frozenxid,
   16558             :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   16559             :             }
   16560             :         }
   16561             : 
   16562             :         /*
   16563             :          * In binary_upgrade mode, restore matviews' populated status by
   16564             :          * poking pg_class directly.  This is pretty ugly, but we can't use
   16565             :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   16566             :          * matview is not populated even though this matview is; in any case,
   16567             :          * we want to transfer the matview's heap storage, not run REFRESH.
   16568             :          */
   16569        9850 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   16570          34 :             tbinfo->relispopulated)
   16571             :         {
   16572          30 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   16573          30 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   16574             :                                  "SET relispopulated = 't'\n"
   16575             :                                  "WHERE oid = ");
   16576          30 :             appendStringLiteralAH(q, qualrelname, fout);
   16577          30 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   16578             :         }
   16579             : 
   16580             :         /*
   16581             :          * Dump additional per-column properties that we can't handle in the
   16582             :          * main CREATE TABLE command.
   16583             :          */
   16584       45462 :         for (j = 0; j < tbinfo->numatts; j++)
   16585             :         {
   16586             :             /* None of this applies to dropped columns */
   16587       35612 :             if (tbinfo->attisdropped[j])
   16588         856 :                 continue;
   16589             : 
   16590             :             /*
   16591             :              * If we didn't dump the column definition explicitly above, and
   16592             :              * it is not-null and did not inherit that property from a parent,
   16593             :              * we have to mark it separately.
   16594             :              */
   16595       34756 :             if (!shouldPrintColumn(dopt, tbinfo, j) &&
   16596         934 :                 tbinfo->notnull_constrs[j] != NULL &&
   16597         200 :                 (!tbinfo->notnull_inh[j] && !tbinfo->ispartition && !dopt->binary_upgrade))
   16598             :             {
   16599             :                 /* No constraint name desired? */
   16600          24 :                 if (tbinfo->notnull_constrs[j][0] == '\0')
   16601          16 :                     appendPQExpBuffer(q,
   16602             :                                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n",
   16603             :                                       foreign, qualrelname,
   16604          16 :                                       fmtId(tbinfo->attnames[j]));
   16605             :                 else
   16606          16 :                     appendPQExpBuffer(q,
   16607             :                                       "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s NOT NULL %s;\n",
   16608             :                                       foreign, qualrelname,
   16609           8 :                                       tbinfo->notnull_constrs[j],
   16610           8 :                                       fmtId(tbinfo->attnames[j]));
   16611             :             }
   16612             : 
   16613             :             /*
   16614             :              * Dump per-column statistics information. We only issue an ALTER
   16615             :              * TABLE statement if the attstattarget entry for this column is
   16616             :              * not the default value.
   16617             :              */
   16618       34756 :             if (tbinfo->attstattarget[j] >= 0)
   16619          66 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   16620             :                                   foreign, qualrelname,
   16621          66 :                                   fmtId(tbinfo->attnames[j]),
   16622          66 :                                   tbinfo->attstattarget[j]);
   16623             : 
   16624             :             /*
   16625             :              * Dump per-column storage information.  The statement is only
   16626             :              * dumped if the storage has been changed from the type's default.
   16627             :              */
   16628       34756 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   16629             :             {
   16630         162 :                 switch (tbinfo->attstorage[j])
   16631             :                 {
   16632          20 :                     case TYPSTORAGE_PLAIN:
   16633          20 :                         storage = "PLAIN";
   16634          20 :                         break;
   16635          76 :                     case TYPSTORAGE_EXTERNAL:
   16636          76 :                         storage = "EXTERNAL";
   16637          76 :                         break;
   16638           0 :                     case TYPSTORAGE_EXTENDED:
   16639           0 :                         storage = "EXTENDED";
   16640           0 :                         break;
   16641          66 :                     case TYPSTORAGE_MAIN:
   16642          66 :                         storage = "MAIN";
   16643          66 :                         break;
   16644           0 :                     default:
   16645           0 :                         storage = NULL;
   16646             :                 }
   16647             : 
   16648             :                 /*
   16649             :                  * Only dump the statement if it's a storage type we recognize
   16650             :                  */
   16651         162 :                 if (storage != NULL)
   16652         162 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   16653             :                                       foreign, qualrelname,
   16654         162 :                                       fmtId(tbinfo->attnames[j]),
   16655             :                                       storage);
   16656             :             }
   16657             : 
   16658             :             /*
   16659             :              * Dump per-column compression, if it's been set.
   16660             :              */
   16661       34756 :             if (!dopt->no_toast_compression)
   16662             :             {
   16663             :                 const char *cmname;
   16664             : 
   16665       34590 :                 switch (tbinfo->attcompression[j])
   16666             :                 {
   16667         114 :                     case 'p':
   16668         114 :                         cmname = "pglz";
   16669         114 :                         break;
   16670         188 :                     case 'l':
   16671         188 :                         cmname = "lz4";
   16672         188 :                         break;
   16673       34288 :                     default:
   16674       34288 :                         cmname = NULL;
   16675       34288 :                         break;
   16676             :                 }
   16677             : 
   16678       34590 :                 if (cmname != NULL)
   16679         302 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   16680             :                                       foreign, qualrelname,
   16681         302 :                                       fmtId(tbinfo->attnames[j]),
   16682             :                                       cmname);
   16683             :             }
   16684             : 
   16685             :             /*
   16686             :              * Dump per-column attributes.
   16687             :              */
   16688       34756 :             if (tbinfo->attoptions[j][0] != '\0')
   16689          66 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   16690             :                                   foreign, qualrelname,
   16691          66 :                                   fmtId(tbinfo->attnames[j]),
   16692          66 :                                   tbinfo->attoptions[j]);
   16693             : 
   16694             :             /*
   16695             :              * Dump per-column fdw options.
   16696             :              */
   16697       34756 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   16698          70 :                 tbinfo->attfdwoptions[j][0] != '\0')
   16699          66 :                 appendPQExpBuffer(q,
   16700             :                                   "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
   16701             :                                   "    %s\n"
   16702             :                                   ");\n",
   16703             :                                   qualrelname,
   16704          66 :                                   fmtId(tbinfo->attnames[j]),
   16705          66 :                                   tbinfo->attfdwoptions[j]);
   16706             :         }                       /* end loop over columns */
   16707             : 
   16708        9850 :         free(partkeydef);
   16709        9850 :         free(ftoptions);
   16710        9850 :         free(srvname);
   16711             :     }
   16712             : 
   16713             :     /*
   16714             :      * dump properties we only have ALTER TABLE syntax for
   16715             :      */
   16716       10542 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   16717        2442 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   16718        1436 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   16719        9780 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   16720             :     {
   16721         138 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   16722             :         {
   16723             :             /* nothing to do, will be set when the index is dumped */
   16724             :         }
   16725         128 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   16726             :         {
   16727         128 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   16728             :                               qualrelname);
   16729             :         }
   16730           0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   16731             :         {
   16732           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   16733             :                               qualrelname);
   16734             :         }
   16735             :     }
   16736             : 
   16737       10542 :     if (tbinfo->forcerowsec)
   16738          10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   16739             :                           qualrelname);
   16740             : 
   16741       10542 :     if (dopt->binary_upgrade)
   16742        1510 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   16743             :                                         reltypename, qrelname,
   16744        1510 :                                         tbinfo->dobj.namespace->dobj.name);
   16745             : 
   16746       10542 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16747             :     {
   16748       10542 :         char       *tablespace = NULL;
   16749       10542 :         char       *tableam = NULL;
   16750             : 
   16751             :         /*
   16752             :          * _selectTablespace() relies on tablespace-enabled objects in the
   16753             :          * default tablespace to have a tablespace of "" (empty string) versus
   16754             :          * non-tablespace-enabled objects to have a tablespace of NULL.
   16755             :          * getTables() sets tbinfo->reltablespace to "" for the default
   16756             :          * tablespace (not NULL).
   16757             :          */
   16758       10542 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   16759        9780 :             tablespace = tbinfo->reltablespace;
   16760             : 
   16761       10542 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   16762        1768 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   16763        9780 :             tableam = tbinfo->amname;
   16764             : 
   16765       10542 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   16766       10542 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   16767             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16768             :                                   .tablespace = tablespace,
   16769             :                                   .tableam = tableam,
   16770             :                                   .relkind = tbinfo->relkind,
   16771             :                                   .owner = tbinfo->rolname,
   16772             :                                   .description = reltypename,
   16773             :                                   .section = tbinfo->postponed_def ?
   16774             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   16775             :                                   .createStmt = q->data,
   16776             :                                   .dropStmt = delq->data));
   16777             :     }
   16778             : 
   16779             :     /* Dump Table Comments */
   16780       10542 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   16781         152 :         dumpTableComment(fout, tbinfo, reltypename);
   16782             : 
   16783             :     /* Dump Table Security Labels */
   16784       10542 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   16785           0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   16786             : 
   16787             :     /* Dump comments on inlined table constraints */
   16788       11598 :     for (j = 0; j < tbinfo->ncheck; j++)
   16789             :     {
   16790        1056 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   16791             : 
   16792        1056 :         if (constr->separate || !constr->conislocal)
   16793         428 :             continue;
   16794             : 
   16795         628 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   16796          76 :             dumpTableConstraintComment(fout, constr);
   16797             :     }
   16798             : 
   16799       10542 :     destroyPQExpBuffer(q);
   16800       10542 :     destroyPQExpBuffer(delq);
   16801       10542 :     free(qrelname);
   16802       10542 :     free(qualrelname);
   16803       10542 : }
   16804             : 
   16805             : /*
   16806             :  * dumpTableAttach
   16807             :  *    write to fout the commands to attach a child partition
   16808             :  *
   16809             :  * Child partitions are always made by creating them separately
   16810             :  * and then using ATTACH PARTITION, rather than using
   16811             :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   16812             :  * any possible discrepancy in column layout, to allow assigning the
   16813             :  * correct tablespace if different, and so that it's possible to restore
   16814             :  * a partition without restoring its parent.  (You'll get an error from
   16815             :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   16816             :  * using "pg_restore -L" if you prefer.)  The last point motivates
   16817             :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   16818             :  * rather than emitting it within the child partition's ArchiveEntry.
   16819             :  */
   16820             : static void
   16821        2476 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   16822             : {
   16823        2476 :     DumpOptions *dopt = fout->dopt;
   16824             :     PQExpBuffer q;
   16825             :     PGresult   *res;
   16826             :     char       *partbound;
   16827             : 
   16828             :     /* Do nothing in data-only dump */
   16829        2476 :     if (dopt->dataOnly)
   16830          42 :         return;
   16831             : 
   16832        2434 :     q = createPQExpBuffer();
   16833             : 
   16834        2434 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   16835             :     {
   16836             :         /* Set up query for partbound details */
   16837          88 :         appendPQExpBufferStr(q,
   16838             :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   16839             : 
   16840          88 :         appendPQExpBufferStr(q,
   16841             :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   16842             :                              "FROM pg_class c "
   16843             :                              "WHERE c.oid = $1");
   16844             : 
   16845          88 :         ExecuteSqlStatement(fout, q->data);
   16846             : 
   16847          88 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   16848             :     }
   16849             : 
   16850        2434 :     printfPQExpBuffer(q,
   16851             :                       "EXECUTE dumpTableAttach('%u')",
   16852        2434 :                       attachinfo->partitionTbl->dobj.catId.oid);
   16853             : 
   16854        2434 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   16855        2434 :     partbound = PQgetvalue(res, 0, 0);
   16856             : 
   16857             :     /* Perform ALTER TABLE on the parent */
   16858        2434 :     printfPQExpBuffer(q,
   16859             :                       "ALTER TABLE ONLY %s ",
   16860        2434 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   16861        2434 :     appendPQExpBuffer(q,
   16862             :                       "ATTACH PARTITION %s %s;\n",
   16863        2434 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   16864             :                       partbound);
   16865             : 
   16866             :     /*
   16867             :      * There is no point in creating a drop query as the drop is done by table
   16868             :      * drop.  (If you think to change this, see also _printTocEntry().)
   16869             :      * Although this object doesn't really have ownership as such, set the
   16870             :      * owner field anyway to ensure that the command is run by the correct
   16871             :      * role at restore time.
   16872             :      */
   16873        2434 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   16874        2434 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   16875             :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   16876             :                               .owner = attachinfo->partitionTbl->rolname,
   16877             :                               .description = "TABLE ATTACH",
   16878             :                               .section = SECTION_PRE_DATA,
   16879             :                               .createStmt = q->data));
   16880             : 
   16881        2434 :     PQclear(res);
   16882        2434 :     destroyPQExpBuffer(q);
   16883             : }
   16884             : 
   16885             : /*
   16886             :  * dumpAttrDef --- dump an attribute's default-value declaration
   16887             :  */
   16888             : static void
   16889        1520 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   16890             : {
   16891        1520 :     DumpOptions *dopt = fout->dopt;
   16892        1520 :     TableInfo  *tbinfo = adinfo->adtable;
   16893        1520 :     int         adnum = adinfo->adnum;
   16894             :     PQExpBuffer q;
   16895             :     PQExpBuffer delq;
   16896             :     char       *qualrelname;
   16897             :     char       *tag;
   16898             :     char       *foreign;
   16899             : 
   16900             :     /* Do nothing in data-only dump */
   16901        1520 :     if (dopt->dataOnly)
   16902           0 :         return;
   16903             : 
   16904             :     /* Skip if not "separate"; it was dumped in the table's definition */
   16905        1520 :     if (!adinfo->separate)
   16906        1232 :         return;
   16907             : 
   16908         288 :     q = createPQExpBuffer();
   16909         288 :     delq = createPQExpBuffer();
   16910             : 
   16911         288 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   16912             : 
   16913         288 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   16914             : 
   16915         288 :     appendPQExpBuffer(q,
   16916             :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   16917         288 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   16918             :                       adinfo->adef_expr);
   16919             : 
   16920         288 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   16921             :                       foreign, qualrelname,
   16922         288 :                       fmtId(tbinfo->attnames[adnum - 1]));
   16923             : 
   16924         288 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   16925             : 
   16926         288 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16927         288 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   16928         288 :                      ARCHIVE_OPTS(.tag = tag,
   16929             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   16930             :                                   .owner = tbinfo->rolname,
   16931             :                                   .description = "DEFAULT",
   16932             :                                   .section = SECTION_PRE_DATA,
   16933             :                                   .createStmt = q->data,
   16934             :                                   .dropStmt = delq->data));
   16935             : 
   16936         288 :     free(tag);
   16937         288 :     destroyPQExpBuffer(q);
   16938         288 :     destroyPQExpBuffer(delq);
   16939         288 :     free(qualrelname);
   16940             : }
   16941             : 
   16942             : /*
   16943             :  * getAttrName: extract the correct name for an attribute
   16944             :  *
   16945             :  * The array tblInfo->attnames[] only provides names of user attributes;
   16946             :  * if a system attribute number is supplied, we have to fake it.
   16947             :  * We also do a little bit of bounds checking for safety's sake.
   16948             :  */
   16949             : static const char *
   16950        3212 : getAttrName(int attrnum, const TableInfo *tblInfo)
   16951             : {
   16952        3212 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   16953        3212 :         return tblInfo->attnames[attrnum - 1];
   16954           0 :     switch (attrnum)
   16955             :     {
   16956           0 :         case SelfItemPointerAttributeNumber:
   16957           0 :             return "ctid";
   16958           0 :         case MinTransactionIdAttributeNumber:
   16959           0 :             return "xmin";
   16960           0 :         case MinCommandIdAttributeNumber:
   16961           0 :             return "cmin";
   16962           0 :         case MaxTransactionIdAttributeNumber:
   16963           0 :             return "xmax";
   16964           0 :         case MaxCommandIdAttributeNumber:
   16965           0 :             return "cmax";
   16966           0 :         case TableOidAttributeNumber:
   16967           0 :             return "tableoid";
   16968             :     }
   16969           0 :     pg_fatal("invalid column number %d for table \"%s\"",
   16970             :              attrnum, tblInfo->dobj.name);
   16971             :     return NULL;                /* keep compiler quiet */
   16972             : }
   16973             : 
   16974             : /*
   16975             :  * dumpIndex
   16976             :  *    write out to fout a user-defined index
   16977             :  */
   16978             : static void
   16979        4244 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   16980             : {
   16981        4244 :     DumpOptions *dopt = fout->dopt;
   16982        4244 :     TableInfo  *tbinfo = indxinfo->indextable;
   16983        4244 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   16984             :     PQExpBuffer q;
   16985             :     PQExpBuffer delq;
   16986             :     char       *qindxname;
   16987             :     char       *qqindxname;
   16988             : 
   16989             :     /* Do nothing in data-only dump */
   16990        4244 :     if (dopt->dataOnly)
   16991         114 :         return;
   16992             : 
   16993        4130 :     q = createPQExpBuffer();
   16994        4130 :     delq = createPQExpBuffer();
   16995             : 
   16996        4130 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   16997        4130 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   16998             : 
   16999             :     /*
   17000             :      * If there's an associated constraint, don't dump the index per se, but
   17001             :      * do dump any comment for it.  (This is safe because dependency ordering
   17002             :      * will have ensured the constraint is emitted first.)  Note that the
   17003             :      * emitted comment has to be shown as depending on the constraint, not the
   17004             :      * index, in such cases.
   17005             :      */
   17006        4130 :     if (!is_constraint)
   17007             :     {
   17008        1892 :         char       *indstatcols = indxinfo->indstatcols;
   17009        1892 :         char       *indstatvals = indxinfo->indstatvals;
   17010        1892 :         char      **indstatcolsarray = NULL;
   17011        1892 :         char      **indstatvalsarray = NULL;
   17012        1892 :         int         nstatcols = 0;
   17013        1892 :         int         nstatvals = 0;
   17014             : 
   17015        1892 :         if (dopt->binary_upgrade)
   17016         296 :             binary_upgrade_set_pg_class_oids(fout, q,
   17017             :                                              indxinfo->dobj.catId.oid, true);
   17018             : 
   17019             :         /* Plain secondary index */
   17020        1892 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   17021             : 
   17022             :         /*
   17023             :          * Append ALTER TABLE commands as needed to set properties that we
   17024             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17025             :          * similar code in dumpConstraint!
   17026             :          */
   17027             : 
   17028             :         /* If the index is clustered, we need to record that. */
   17029        1892 :         if (indxinfo->indisclustered)
   17030             :         {
   17031           0 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17032           0 :                               fmtQualifiedDumpable(tbinfo));
   17033             :             /* index name is not qualified in this syntax */
   17034           0 :             appendPQExpBuffer(q, " ON %s;\n",
   17035             :                               qindxname);
   17036             :         }
   17037             : 
   17038             :         /*
   17039             :          * If the index has any statistics on some of its columns, generate
   17040             :          * the associated ALTER INDEX queries.
   17041             :          */
   17042        1892 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   17043             :         {
   17044             :             int         j;
   17045             : 
   17046          66 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   17047           0 :                 pg_fatal("could not parse index statistic columns");
   17048          66 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   17049           0 :                 pg_fatal("could not parse index statistic values");
   17050          66 :             if (nstatcols != nstatvals)
   17051           0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   17052             : 
   17053         198 :             for (j = 0; j < nstatcols; j++)
   17054             :             {
   17055         132 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   17056             : 
   17057             :                 /*
   17058             :                  * Note that this is a column number, so no quotes should be
   17059             :                  * used.
   17060             :                  */
   17061         132 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   17062         132 :                                   indstatcolsarray[j]);
   17063         132 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   17064         132 :                                   indstatvalsarray[j]);
   17065             :             }
   17066             :         }
   17067             : 
   17068             :         /* Indexes can depend on extensions */
   17069        1892 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17070             :                                     "pg_catalog.pg_class",
   17071             :                                     "INDEX", qqindxname);
   17072             : 
   17073             :         /* If the index defines identity, we need to record that. */
   17074        1892 :         if (indxinfo->indisreplident)
   17075             :         {
   17076           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17077           0 :                               fmtQualifiedDumpable(tbinfo));
   17078             :             /* index name is not qualified in this syntax */
   17079           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17080             :                               qindxname);
   17081             :         }
   17082             : 
   17083        1892 :         appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   17084             : 
   17085        1892 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17086        1892 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   17087        1892 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   17088             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17089             :                                       .tablespace = indxinfo->tablespace,
   17090             :                                       .owner = tbinfo->rolname,
   17091             :                                       .description = "INDEX",
   17092             :                                       .section = SECTION_POST_DATA,
   17093             :                                       .createStmt = q->data,
   17094             :                                       .dropStmt = delq->data));
   17095             : 
   17096        1892 :         free(indstatcolsarray);
   17097        1892 :         free(indstatvalsarray);
   17098             :     }
   17099             : 
   17100             :     /* Dump Index Comments */
   17101        4130 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17102          30 :         dumpComment(fout, "INDEX", qindxname,
   17103          30 :                     tbinfo->dobj.namespace->dobj.name,
   17104             :                     tbinfo->rolname,
   17105             :                     indxinfo->dobj.catId, 0,
   17106             :                     is_constraint ? indxinfo->indexconstraint :
   17107             :                     indxinfo->dobj.dumpId);
   17108             : 
   17109        4130 :     destroyPQExpBuffer(q);
   17110        4130 :     destroyPQExpBuffer(delq);
   17111        4130 :     free(qindxname);
   17112        4130 :     free(qqindxname);
   17113             : }
   17114             : 
   17115             : /*
   17116             :  * dumpIndexAttach
   17117             :  *    write out to fout a partitioned-index attachment clause
   17118             :  */
   17119             : static void
   17120        1086 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   17121             : {
   17122             :     /* Do nothing in data-only dump */
   17123        1086 :     if (fout->dopt->dataOnly)
   17124          48 :         return;
   17125             : 
   17126        1038 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17127             :     {
   17128        1038 :         PQExpBuffer q = createPQExpBuffer();
   17129             : 
   17130        1038 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   17131        1038 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   17132        1038 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   17133        1038 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   17134             : 
   17135             :         /*
   17136             :          * There is no point in creating a drop query as the drop is done by
   17137             :          * index drop.  (If you think to change this, see also
   17138             :          * _printTocEntry().)  Although this object doesn't really have
   17139             :          * ownership as such, set the owner field anyway to ensure that the
   17140             :          * command is run by the correct role at restore time.
   17141             :          */
   17142        1038 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   17143        1038 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   17144             :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   17145             :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   17146             :                                   .description = "INDEX ATTACH",
   17147             :                                   .section = SECTION_POST_DATA,
   17148             :                                   .createStmt = q->data));
   17149             : 
   17150        1038 :         destroyPQExpBuffer(q);
   17151             :     }
   17152             : }
   17153             : 
   17154             : /*
   17155             :  * dumpStatisticsExt
   17156             :  *    write out to fout an extended statistics object
   17157             :  */
   17158             : static void
   17159         254 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   17160             : {
   17161         254 :     DumpOptions *dopt = fout->dopt;
   17162             :     PQExpBuffer q;
   17163             :     PQExpBuffer delq;
   17164             :     PQExpBuffer query;
   17165             :     char       *qstatsextname;
   17166             :     PGresult   *res;
   17167             :     char       *stxdef;
   17168             : 
   17169             :     /* Do nothing in data-only dump */
   17170         254 :     if (dopt->dataOnly)
   17171          18 :         return;
   17172             : 
   17173         236 :     q = createPQExpBuffer();
   17174         236 :     delq = createPQExpBuffer();
   17175         236 :     query = createPQExpBuffer();
   17176             : 
   17177         236 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   17178             : 
   17179         236 :     appendPQExpBuffer(query, "SELECT "
   17180             :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   17181             :                       statsextinfo->dobj.catId.oid);
   17182             : 
   17183         236 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17184             : 
   17185         236 :     stxdef = PQgetvalue(res, 0, 0);
   17186             : 
   17187             :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   17188         236 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   17189             : 
   17190             :     /*
   17191             :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   17192             :      * for this statistics object is not the default value.
   17193             :      */
   17194         236 :     if (statsextinfo->stattarget >= 0)
   17195             :     {
   17196          66 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   17197          66 :                           fmtQualifiedDumpable(statsextinfo));
   17198          66 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   17199             :                           statsextinfo->stattarget);
   17200             :     }
   17201             : 
   17202         236 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   17203         236 :                       fmtQualifiedDumpable(statsextinfo));
   17204             : 
   17205         236 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17206         236 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   17207             :                      statsextinfo->dobj.dumpId,
   17208         236 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   17209             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   17210             :                                   .owner = statsextinfo->rolname,
   17211             :                                   .description = "STATISTICS",
   17212             :                                   .section = SECTION_POST_DATA,
   17213             :                                   .createStmt = q->data,
   17214             :                                   .dropStmt = delq->data));
   17215             : 
   17216             :     /* Dump Statistics Comments */
   17217         236 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17218           0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   17219           0 :                     statsextinfo->dobj.namespace->dobj.name,
   17220             :                     statsextinfo->rolname,
   17221             :                     statsextinfo->dobj.catId, 0,
   17222             :                     statsextinfo->dobj.dumpId);
   17223             : 
   17224         236 :     PQclear(res);
   17225         236 :     destroyPQExpBuffer(q);
   17226         236 :     destroyPQExpBuffer(delq);
   17227         236 :     destroyPQExpBuffer(query);
   17228         236 :     free(qstatsextname);
   17229             : }
   17230             : 
   17231             : /*
   17232             :  * dumpConstraint
   17233             :  *    write out to fout a user-defined constraint
   17234             :  */
   17235             : static void
   17236        3886 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   17237             : {
   17238        3886 :     DumpOptions *dopt = fout->dopt;
   17239        3886 :     TableInfo  *tbinfo = coninfo->contable;
   17240             :     PQExpBuffer q;
   17241             :     PQExpBuffer delq;
   17242        3886 :     char       *tag = NULL;
   17243             :     char       *foreign;
   17244             : 
   17245             :     /* Do nothing in data-only dump */
   17246        3886 :     if (dopt->dataOnly)
   17247          94 :         return;
   17248             : 
   17249        3792 :     q = createPQExpBuffer();
   17250        3792 :     delq = createPQExpBuffer();
   17251             : 
   17252        7418 :     foreign = tbinfo &&
   17253        3792 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   17254             : 
   17255        3792 :     if (coninfo->contype == 'p' ||
   17256        1822 :         coninfo->contype == 'u' ||
   17257        1574 :         coninfo->contype == 'x')
   17258        2238 :     {
   17259             :         /* Index-related constraint */
   17260             :         IndxInfo   *indxinfo;
   17261             :         int         k;
   17262             : 
   17263        2238 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   17264             : 
   17265        2238 :         if (indxinfo == NULL)
   17266           0 :             pg_fatal("missing index for constraint \"%s\"",
   17267             :                      coninfo->dobj.name);
   17268             : 
   17269        2238 :         if (dopt->binary_upgrade)
   17270         254 :             binary_upgrade_set_pg_class_oids(fout, q,
   17271             :                                              indxinfo->dobj.catId.oid, true);
   17272             : 
   17273        2238 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   17274        2238 :                           fmtQualifiedDumpable(tbinfo));
   17275        2238 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   17276        2238 :                           fmtId(coninfo->dobj.name));
   17277             : 
   17278        2238 :         if (coninfo->condef)
   17279             :         {
   17280             :             /* pg_get_constraintdef should have provided everything */
   17281          20 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   17282             :         }
   17283             :         else
   17284             :         {
   17285        2218 :             appendPQExpBufferStr(q,
   17286        2218 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   17287             : 
   17288             :             /*
   17289             :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   17290             :              * indexes. Being able to create this was fixed, but we need to
   17291             :              * make the index distinct in order to be able to restore the
   17292             :              * dump.
   17293             :              */
   17294        2218 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   17295           0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   17296        2218 :             appendPQExpBufferStr(q, " (");
   17297        5350 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   17298             :             {
   17299        3132 :                 int         indkey = (int) indxinfo->indkeys[k];
   17300             :                 const char *attname;
   17301             : 
   17302        3132 :                 if (indkey == InvalidAttrNumber)
   17303           0 :                     break;
   17304        3132 :                 attname = getAttrName(indkey, tbinfo);
   17305             : 
   17306        3132 :                 appendPQExpBuffer(q, "%s%s",
   17307             :                                   (k == 0) ? "" : ", ",
   17308             :                                   fmtId(attname));
   17309             :             }
   17310        2218 :             if (coninfo->conperiod)
   17311         222 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   17312             : 
   17313        2218 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   17314          40 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   17315             : 
   17316        2298 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   17317             :             {
   17318          80 :                 int         indkey = (int) indxinfo->indkeys[k];
   17319             :                 const char *attname;
   17320             : 
   17321          80 :                 if (indkey == InvalidAttrNumber)
   17322           0 :                     break;
   17323          80 :                 attname = getAttrName(indkey, tbinfo);
   17324             : 
   17325         160 :                 appendPQExpBuffer(q, "%s%s",
   17326          80 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   17327             :                                   fmtId(attname));
   17328             :             }
   17329             : 
   17330        2218 :             appendPQExpBufferChar(q, ')');
   17331             : 
   17332        2218 :             if (nonemptyReloptions(indxinfo->indreloptions))
   17333             :             {
   17334           0 :                 appendPQExpBufferStr(q, " WITH (");
   17335           0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   17336           0 :                 appendPQExpBufferChar(q, ')');
   17337             :             }
   17338             : 
   17339        2218 :             if (coninfo->condeferrable)
   17340             :             {
   17341          50 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   17342          50 :                 if (coninfo->condeferred)
   17343          30 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   17344             :             }
   17345             : 
   17346        2218 :             appendPQExpBufferStr(q, ";\n");
   17347             :         }
   17348             : 
   17349             :         /*
   17350             :          * Append ALTER TABLE commands as needed to set properties that we
   17351             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17352             :          * similar code in dumpIndex!
   17353             :          */
   17354             : 
   17355             :         /*
   17356             :          * Drop any not-null constraints that were added to support the PK,
   17357             :          * but leave them alone if they have a definition coming from their
   17358             :          * parent.
   17359             :          */
   17360        2238 :         if (coninfo->contype == 'p')
   17361        7504 :             for (int i = 0; i < tbinfo->numatts; i++)
   17362        5534 :                 if (tbinfo->notnull_throwaway[i] &&
   17363        1436 :                     !tbinfo->notnull_inh[i])
   17364        1436 :                     appendPQExpBuffer(q, "\nALTER TABLE ONLY %s DROP CONSTRAINT %s;",
   17365        1436 :                                       fmtQualifiedDumpable(tbinfo),
   17366        1436 :                                       tbinfo->notnull_constrs[i]);
   17367             : 
   17368             :         /* If the index is clustered, we need to record that. */
   17369        2238 :         if (indxinfo->indisclustered)
   17370             :         {
   17371          66 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17372          66 :                               fmtQualifiedDumpable(tbinfo));
   17373             :             /* index name is not qualified in this syntax */
   17374          66 :             appendPQExpBuffer(q, " ON %s;\n",
   17375          66 :                               fmtId(indxinfo->dobj.name));
   17376             :         }
   17377             : 
   17378             :         /* If the index defines identity, we need to record that. */
   17379        2238 :         if (indxinfo->indisreplident)
   17380             :         {
   17381          10 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17382          10 :                               fmtQualifiedDumpable(tbinfo));
   17383             :             /* index name is not qualified in this syntax */
   17384          10 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17385          10 :                               fmtId(indxinfo->dobj.name));
   17386             :         }
   17387             : 
   17388             :         /* Indexes can depend on extensions */
   17389        2238 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17390             :                                     "pg_catalog.pg_class", "INDEX",
   17391        2238 :                                     fmtQualifiedDumpable(indxinfo));
   17392             : 
   17393        2238 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   17394        2238 :                           fmtQualifiedDumpable(tbinfo));
   17395        2238 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17396        2238 :                           fmtId(coninfo->dobj.name));
   17397             : 
   17398        2238 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17399             : 
   17400        2238 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17401        2238 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17402        2238 :                          ARCHIVE_OPTS(.tag = tag,
   17403             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17404             :                                       .tablespace = indxinfo->tablespace,
   17405             :                                       .owner = tbinfo->rolname,
   17406             :                                       .description = "CONSTRAINT",
   17407             :                                       .section = SECTION_POST_DATA,
   17408             :                                       .createStmt = q->data,
   17409             :                                       .dropStmt = delq->data));
   17410             :     }
   17411        1554 :     else if (coninfo->contype == 'f')
   17412             :     {
   17413             :         char       *only;
   17414             : 
   17415             :         /*
   17416             :          * Foreign keys on partitioned tables are always declared as
   17417             :          * inheriting to partitions; for all other cases, emit them as
   17418             :          * applying ONLY directly to the named table, because that's how they
   17419             :          * work for regular inherited tables.
   17420             :          */
   17421         332 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   17422             : 
   17423             :         /*
   17424             :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   17425             :          * current table data is not processed
   17426             :          */
   17427         332 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   17428         332 :                           only, fmtQualifiedDumpable(tbinfo));
   17429         332 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17430         332 :                           fmtId(coninfo->dobj.name),
   17431             :                           coninfo->condef);
   17432             : 
   17433         332 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   17434         332 :                           only, fmtQualifiedDumpable(tbinfo));
   17435         332 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17436         332 :                           fmtId(coninfo->dobj.name));
   17437             : 
   17438         332 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17439             : 
   17440         332 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17441         332 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17442         332 :                          ARCHIVE_OPTS(.tag = tag,
   17443             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17444             :                                       .owner = tbinfo->rolname,
   17445             :                                       .description = "FK CONSTRAINT",
   17446             :                                       .section = SECTION_POST_DATA,
   17447             :                                       .createStmt = q->data,
   17448             :                                       .dropStmt = delq->data));
   17449             :     }
   17450        1222 :     else if (coninfo->contype == 'c' && tbinfo)
   17451             :     {
   17452             :         /* CHECK constraint on a table */
   17453             : 
   17454             :         /* Ignore if not to be dumped separately, or if it was inherited */
   17455        1056 :         if (coninfo->separate && coninfo->conislocal)
   17456             :         {
   17457             :             /* not ONLY since we want it to propagate to children */
   17458          50 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   17459          50 :                               fmtQualifiedDumpable(tbinfo));
   17460          50 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17461          50 :                               fmtId(coninfo->dobj.name),
   17462             :                               coninfo->condef);
   17463             : 
   17464          50 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   17465          50 :                               fmtQualifiedDumpable(tbinfo));
   17466          50 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17467          50 :                               fmtId(coninfo->dobj.name));
   17468             : 
   17469          50 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17470             : 
   17471          50 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17472          50 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17473          50 :                              ARCHIVE_OPTS(.tag = tag,
   17474             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   17475             :                                           .owner = tbinfo->rolname,
   17476             :                                           .description = "CHECK CONSTRAINT",
   17477             :                                           .section = SECTION_POST_DATA,
   17478             :                                           .createStmt = q->data,
   17479             :                                           .dropStmt = delq->data));
   17480             :         }
   17481             :     }
   17482         166 :     else if (coninfo->contype == 'c' && tbinfo == NULL)
   17483         166 :     {
   17484             :         /* CHECK constraint on a domain */
   17485         166 :         TypeInfo   *tyinfo = coninfo->condomain;
   17486             : 
   17487             :         /* Ignore if not to be dumped separately */
   17488         166 :         if (coninfo->separate)
   17489             :         {
   17490           0 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   17491           0 :                               fmtQualifiedDumpable(tyinfo));
   17492           0 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17493           0 :                               fmtId(coninfo->dobj.name),
   17494             :                               coninfo->condef);
   17495             : 
   17496           0 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   17497           0 :                               fmtQualifiedDumpable(tyinfo));
   17498           0 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17499           0 :                               fmtId(coninfo->dobj.name));
   17500             : 
   17501           0 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   17502             : 
   17503           0 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17504           0 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17505           0 :                              ARCHIVE_OPTS(.tag = tag,
   17506             :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   17507             :                                           .owner = tyinfo->rolname,
   17508             :                                           .description = "CHECK CONSTRAINT",
   17509             :                                           .section = SECTION_POST_DATA,
   17510             :                                           .createStmt = q->data,
   17511             :                                           .dropStmt = delq->data));
   17512             :         }
   17513             :     }
   17514             :     else
   17515             :     {
   17516           0 :         pg_fatal("unrecognized constraint type: %c",
   17517             :                  coninfo->contype);
   17518             :     }
   17519             : 
   17520             :     /* Dump Constraint Comments --- only works for table constraints */
   17521        3792 :     if (tbinfo && coninfo->separate &&
   17522        2650 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17523          20 :         dumpTableConstraintComment(fout, coninfo);
   17524             : 
   17525        3792 :     free(tag);
   17526        3792 :     destroyPQExpBuffer(q);
   17527        3792 :     destroyPQExpBuffer(delq);
   17528             : }
   17529             : 
   17530             : /*
   17531             :  * dumpTableConstraintComment --- dump a constraint's comment if any
   17532             :  *
   17533             :  * This is split out because we need the function in two different places
   17534             :  * depending on whether the constraint is dumped as part of CREATE TABLE
   17535             :  * or as a separate ALTER command.
   17536             :  */
   17537             : static void
   17538          96 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   17539             : {
   17540          96 :     TableInfo  *tbinfo = coninfo->contable;
   17541          96 :     PQExpBuffer conprefix = createPQExpBuffer();
   17542             :     char       *qtabname;
   17543             : 
   17544          96 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   17545             : 
   17546          96 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   17547          96 :                       fmtId(coninfo->dobj.name));
   17548             : 
   17549          96 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17550          96 :         dumpComment(fout, conprefix->data, qtabname,
   17551          96 :                     tbinfo->dobj.namespace->dobj.name,
   17552             :                     tbinfo->rolname,
   17553             :                     coninfo->dobj.catId, 0,
   17554          96 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   17555             : 
   17556          96 :     destroyPQExpBuffer(conprefix);
   17557          96 :     free(qtabname);
   17558          96 : }
   17559             : 
   17560             : /*
   17561             :  * dumpSequence
   17562             :  *    write the declaration (not data) of one user-defined sequence
   17563             :  */
   17564             : static void
   17565         686 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   17566             : {
   17567         686 :     DumpOptions *dopt = fout->dopt;
   17568             :     PGresult   *res;
   17569             :     char       *startv,
   17570             :                *incby,
   17571             :                *maxv,
   17572             :                *minv,
   17573             :                *cache,
   17574             :                *seqtype;
   17575             :     bool        cycled;
   17576             :     bool        is_ascending;
   17577             :     int64       default_minv,
   17578             :                 default_maxv;
   17579             :     char        bufm[32],
   17580             :                 bufx[32];
   17581         686 :     PQExpBuffer query = createPQExpBuffer();
   17582         686 :     PQExpBuffer delqry = createPQExpBuffer();
   17583             :     char       *qseqname;
   17584         686 :     TableInfo  *owning_tab = NULL;
   17585             : 
   17586         686 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   17587             : 
   17588         686 :     if (fout->remoteVersion >= 100000)
   17589             :     {
   17590         686 :         appendPQExpBuffer(query,
   17591             :                           "SELECT format_type(seqtypid, NULL), "
   17592             :                           "seqstart, seqincrement, "
   17593             :                           "seqmax, seqmin, "
   17594             :                           "seqcache, seqcycle "
   17595             :                           "FROM pg_catalog.pg_sequence "
   17596             :                           "WHERE seqrelid = '%u'::oid",
   17597             :                           tbinfo->dobj.catId.oid);
   17598             :     }
   17599             :     else
   17600             :     {
   17601             :         /*
   17602             :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   17603             :          *
   17604             :          * Note: it might seem that 'bigint' potentially needs to be
   17605             :          * schema-qualified, but actually that's a keyword.
   17606             :          */
   17607           0 :         appendPQExpBuffer(query,
   17608             :                           "SELECT 'bigint' AS sequence_type, "
   17609             :                           "start_value, increment_by, max_value, min_value, "
   17610             :                           "cache_value, is_cycled FROM %s",
   17611           0 :                           fmtQualifiedDumpable(tbinfo));
   17612             :     }
   17613             : 
   17614         686 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17615             : 
   17616         686 :     if (PQntuples(res) != 1)
   17617           0 :         pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   17618             :                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   17619             :                           PQntuples(res)),
   17620             :                  tbinfo->dobj.name, PQntuples(res));
   17621             : 
   17622         686 :     seqtype = PQgetvalue(res, 0, 0);
   17623         686 :     startv = PQgetvalue(res, 0, 1);
   17624         686 :     incby = PQgetvalue(res, 0, 2);
   17625         686 :     maxv = PQgetvalue(res, 0, 3);
   17626         686 :     minv = PQgetvalue(res, 0, 4);
   17627         686 :     cache = PQgetvalue(res, 0, 5);
   17628         686 :     cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   17629             : 
   17630             :     /* Calculate default limits for a sequence of this type */
   17631         686 :     is_ascending = (incby[0] != '-');
   17632         686 :     if (strcmp(seqtype, "smallint") == 0)
   17633             :     {
   17634          50 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   17635          50 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   17636             :     }
   17637         636 :     else if (strcmp(seqtype, "integer") == 0)
   17638             :     {
   17639         514 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   17640         514 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   17641             :     }
   17642         122 :     else if (strcmp(seqtype, "bigint") == 0)
   17643             :     {
   17644         122 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   17645         122 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   17646             :     }
   17647             :     else
   17648             :     {
   17649           0 :         pg_fatal("unrecognized sequence type: %s", seqtype);
   17650             :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   17651             :     }
   17652             : 
   17653             :     /*
   17654             :      * 64-bit strtol() isn't very portable, so convert the limits to strings
   17655             :      * and compare that way.
   17656             :      */
   17657         686 :     snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
   17658         686 :     snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
   17659             : 
   17660             :     /* Don't print minv/maxv if they match the respective default limit */
   17661         686 :     if (strcmp(minv, bufm) == 0)
   17662         656 :         minv = NULL;
   17663         686 :     if (strcmp(maxv, bufx) == 0)
   17664         656 :         maxv = NULL;
   17665             : 
   17666             :     /*
   17667             :      * Identity sequences are not to be dropped separately.
   17668             :      */
   17669         686 :     if (!tbinfo->is_identity_sequence)
   17670             :     {
   17671         410 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   17672         410 :                           fmtQualifiedDumpable(tbinfo));
   17673             :     }
   17674             : 
   17675         686 :     resetPQExpBuffer(query);
   17676             : 
   17677         686 :     if (dopt->binary_upgrade)
   17678             :     {
   17679         110 :         binary_upgrade_set_pg_class_oids(fout, query,
   17680             :                                          tbinfo->dobj.catId.oid, false);
   17681             : 
   17682             :         /*
   17683             :          * In older PG versions a sequence will have a pg_type entry, but v14
   17684             :          * and up don't use that, so don't attempt to preserve the type OID.
   17685             :          */
   17686             :     }
   17687             : 
   17688         686 :     if (tbinfo->is_identity_sequence)
   17689             :     {
   17690         276 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   17691             : 
   17692         276 :         appendPQExpBuffer(query,
   17693             :                           "ALTER TABLE %s ",
   17694         276 :                           fmtQualifiedDumpable(owning_tab));
   17695         276 :         appendPQExpBuffer(query,
   17696             :                           "ALTER COLUMN %s ADD GENERATED ",
   17697         276 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   17698         276 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   17699         186 :             appendPQExpBufferStr(query, "ALWAYS");
   17700          90 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   17701          90 :             appendPQExpBufferStr(query, "BY DEFAULT");
   17702         276 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   17703         276 :                           fmtQualifiedDumpable(tbinfo));
   17704             :     }
   17705             :     else
   17706             :     {
   17707         410 :         appendPQExpBuffer(query,
   17708             :                           "CREATE %sSEQUENCE %s\n",
   17709         410 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   17710             :                           "UNLOGGED " : "",
   17711         410 :                           fmtQualifiedDumpable(tbinfo));
   17712             : 
   17713         410 :         if (strcmp(seqtype, "bigint") != 0)
   17714         318 :             appendPQExpBuffer(query, "    AS %s\n", seqtype);
   17715             :     }
   17716             : 
   17717         686 :     appendPQExpBuffer(query, "    START WITH %s\n", startv);
   17718             : 
   17719         686 :     appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
   17720             : 
   17721         686 :     if (minv)
   17722          30 :         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
   17723             :     else
   17724         656 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   17725             : 
   17726         686 :     if (maxv)
   17727          30 :         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
   17728             :     else
   17729         656 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   17730             : 
   17731         686 :     appendPQExpBuffer(query,
   17732             :                       "    CACHE %s%s",
   17733             :                       cache, (cycled ? "\n    CYCLE" : ""));
   17734             : 
   17735         686 :     if (tbinfo->is_identity_sequence)
   17736             :     {
   17737         276 :         appendPQExpBufferStr(query, "\n);\n");
   17738         276 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   17739           0 :             appendPQExpBuffer(query,
   17740             :                               "ALTER SEQUENCE %s SET %s;\n",
   17741           0 :                               fmtQualifiedDumpable(tbinfo),
   17742           0 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   17743             :                               "UNLOGGED" : "LOGGED");
   17744             :     }
   17745             :     else
   17746         410 :         appendPQExpBufferStr(query, ";\n");
   17747             : 
   17748             :     /* binary_upgrade:  no need to clear TOAST table oid */
   17749             : 
   17750         686 :     if (dopt->binary_upgrade)
   17751         110 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   17752             :                                         "SEQUENCE", qseqname,
   17753         110 :                                         tbinfo->dobj.namespace->dobj.name);
   17754             : 
   17755         686 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17756         686 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   17757         686 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17758             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17759             :                                   .owner = tbinfo->rolname,
   17760             :                                   .description = "SEQUENCE",
   17761             :                                   .section = SECTION_PRE_DATA,
   17762             :                                   .createStmt = query->data,
   17763             :                                   .dropStmt = delqry->data));
   17764             : 
   17765             :     /*
   17766             :      * If the sequence is owned by a table column, emit the ALTER for it as a
   17767             :      * separate TOC entry immediately following the sequence's own entry. It's
   17768             :      * OK to do this rather than using full sorting logic, because the
   17769             :      * dependency that tells us it's owned will have forced the table to be
   17770             :      * created first.  We can't just include the ALTER in the TOC entry
   17771             :      * because it will fail if we haven't reassigned the sequence owner to
   17772             :      * match the table's owner.
   17773             :      *
   17774             :      * We need not schema-qualify the table reference because both sequence
   17775             :      * and table must be in the same schema.
   17776             :      */
   17777         686 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   17778             :     {
   17779         228 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   17780             : 
   17781         228 :         if (owning_tab == NULL)
   17782           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   17783             :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   17784             : 
   17785         228 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17786             :         {
   17787         224 :             resetPQExpBuffer(query);
   17788         224 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   17789         224 :                               fmtQualifiedDumpable(tbinfo));
   17790         224 :             appendPQExpBuffer(query, " OWNED BY %s",
   17791         224 :                               fmtQualifiedDumpable(owning_tab));
   17792         224 :             appendPQExpBuffer(query, ".%s;\n",
   17793         224 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   17794             : 
   17795         224 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17796         224 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   17797         224 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17798             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   17799             :                                           .owner = tbinfo->rolname,
   17800             :                                           .description = "SEQUENCE OWNED BY",
   17801             :                                           .section = SECTION_PRE_DATA,
   17802             :                                           .createStmt = query->data,
   17803             :                                           .deps = &(tbinfo->dobj.dumpId),
   17804             :                                           .nDeps = 1));
   17805             :         }
   17806             :     }
   17807             : 
   17808             :     /* Dump Sequence Comments and Security Labels */
   17809         686 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17810           0 :         dumpComment(fout, "SEQUENCE", qseqname,
   17811           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   17812             :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   17813             : 
   17814         686 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   17815           0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   17816           0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   17817             :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   17818             : 
   17819         686 :     PQclear(res);
   17820             : 
   17821         686 :     destroyPQExpBuffer(query);
   17822         686 :     destroyPQExpBuffer(delqry);
   17823         686 :     free(qseqname);
   17824         686 : }
   17825             : 
   17826             : /*
   17827             :  * dumpSequenceData
   17828             :  *    write the data of one user-defined sequence
   17829             :  */
   17830             : static void
   17831         722 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   17832             : {
   17833         722 :     TableInfo  *tbinfo = tdinfo->tdtable;
   17834             :     PGresult   *res;
   17835             :     char       *last;
   17836             :     bool        called;
   17837         722 :     PQExpBuffer query = createPQExpBuffer();
   17838             : 
   17839         722 :     appendPQExpBuffer(query,
   17840             :                       "SELECT last_value, is_called FROM %s",
   17841         722 :                       fmtQualifiedDumpable(tbinfo));
   17842             : 
   17843         722 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   17844             : 
   17845         722 :     if (PQntuples(res) != 1)
   17846           0 :         pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   17847             :                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   17848             :                           PQntuples(res)),
   17849             :                  tbinfo->dobj.name, PQntuples(res));
   17850             : 
   17851         722 :     last = PQgetvalue(res, 0, 0);
   17852         722 :     called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   17853             : 
   17854         722 :     resetPQExpBuffer(query);
   17855         722 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   17856         722 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   17857         722 :     appendPQExpBuffer(query, ", %s, %s);\n",
   17858             :                       last, (called ? "true" : "false"));
   17859             : 
   17860         722 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   17861         722 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   17862         722 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17863             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17864             :                                   .owner = tbinfo->rolname,
   17865             :                                   .description = "SEQUENCE SET",
   17866             :                                   .section = SECTION_DATA,
   17867             :                                   .createStmt = query->data,
   17868             :                                   .deps = &(tbinfo->dobj.dumpId),
   17869             :                                   .nDeps = 1));
   17870             : 
   17871         722 :     PQclear(res);
   17872             : 
   17873         722 :     destroyPQExpBuffer(query);
   17874         722 : }
   17875             : 
   17876             : /*
   17877             :  * dumpTrigger
   17878             :  *    write the declaration of one user-defined table trigger
   17879             :  */
   17880             : static void
   17881         986 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   17882             : {
   17883         986 :     DumpOptions *dopt = fout->dopt;
   17884         986 :     TableInfo  *tbinfo = tginfo->tgtable;
   17885             :     PQExpBuffer query;
   17886             :     PQExpBuffer delqry;
   17887             :     PQExpBuffer trigprefix;
   17888             :     PQExpBuffer trigidentity;
   17889             :     char       *qtabname;
   17890             :     char       *tag;
   17891             : 
   17892             :     /* Do nothing in data-only dump */
   17893         986 :     if (dopt->dataOnly)
   17894          32 :         return;
   17895             : 
   17896         954 :     query = createPQExpBuffer();
   17897         954 :     delqry = createPQExpBuffer();
   17898         954 :     trigprefix = createPQExpBuffer();
   17899         954 :     trigidentity = createPQExpBuffer();
   17900             : 
   17901         954 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   17902             : 
   17903         954 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   17904         954 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   17905             : 
   17906         954 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   17907         954 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   17908             : 
   17909             :     /* Triggers can depend on extensions */
   17910         954 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   17911             :                                 "pg_catalog.pg_trigger", "TRIGGER",
   17912         954 :                                 trigidentity->data);
   17913             : 
   17914         954 :     if (tginfo->tgispartition)
   17915             :     {
   17916             :         Assert(tbinfo->ispartition);
   17917             : 
   17918             :         /*
   17919             :          * Partition triggers only appear here because their 'tgenabled' flag
   17920             :          * differs from its parent's.  The trigger is created already, so
   17921             :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   17922             :          * DROP query too, so that pg_dump --create does not cause errors.)
   17923             :          */
   17924         224 :         resetPQExpBuffer(query);
   17925         224 :         resetPQExpBuffer(delqry);
   17926         224 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   17927         224 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   17928         224 :                           fmtQualifiedDumpable(tbinfo));
   17929         224 :         switch (tginfo->tgenabled)
   17930             :         {
   17931          78 :             case 'f':
   17932             :             case 'D':
   17933          78 :                 appendPQExpBufferStr(query, "DISABLE");
   17934          78 :                 break;
   17935           0 :             case 't':
   17936             :             case 'O':
   17937           0 :                 appendPQExpBufferStr(query, "ENABLE");
   17938           0 :                 break;
   17939          68 :             case 'R':
   17940          68 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   17941          68 :                 break;
   17942          78 :             case 'A':
   17943          78 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   17944          78 :                 break;
   17945             :         }
   17946         224 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   17947         224 :                           fmtId(tginfo->dobj.name));
   17948             :     }
   17949         730 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   17950             :     {
   17951           0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   17952           0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   17953           0 :                           fmtQualifiedDumpable(tbinfo));
   17954           0 :         switch (tginfo->tgenabled)
   17955             :         {
   17956           0 :             case 'D':
   17957             :             case 'f':
   17958           0 :                 appendPQExpBufferStr(query, "DISABLE");
   17959           0 :                 break;
   17960           0 :             case 'A':
   17961           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   17962           0 :                 break;
   17963           0 :             case 'R':
   17964           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   17965           0 :                 break;
   17966           0 :             default:
   17967           0 :                 appendPQExpBufferStr(query, "ENABLE");
   17968           0 :                 break;
   17969             :         }
   17970           0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   17971           0 :                           fmtId(tginfo->dobj.name));
   17972             :     }
   17973             : 
   17974         954 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   17975         954 :                       fmtId(tginfo->dobj.name));
   17976             : 
   17977         954 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   17978             : 
   17979         954 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17980         954 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   17981         954 :                      ARCHIVE_OPTS(.tag = tag,
   17982             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17983             :                                   .owner = tbinfo->rolname,
   17984             :                                   .description = "TRIGGER",
   17985             :                                   .section = SECTION_POST_DATA,
   17986             :                                   .createStmt = query->data,
   17987             :                                   .dropStmt = delqry->data));
   17988             : 
   17989         954 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17990           0 :         dumpComment(fout, trigprefix->data, qtabname,
   17991           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   17992             :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   17993             : 
   17994         954 :     free(tag);
   17995         954 :     destroyPQExpBuffer(query);
   17996         954 :     destroyPQExpBuffer(delqry);
   17997         954 :     destroyPQExpBuffer(trigprefix);
   17998         954 :     destroyPQExpBuffer(trigidentity);
   17999         954 :     free(qtabname);
   18000             : }
   18001             : 
   18002             : /*
   18003             :  * dumpEventTrigger
   18004             :  *    write the declaration of one user-defined event trigger
   18005             :  */
   18006             : static void
   18007          80 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   18008             : {
   18009          80 :     DumpOptions *dopt = fout->dopt;
   18010             :     PQExpBuffer query;
   18011             :     PQExpBuffer delqry;
   18012             :     char       *qevtname;
   18013             : 
   18014             :     /* Do nothing in data-only dump */
   18015          80 :     if (dopt->dataOnly)
   18016           6 :         return;
   18017             : 
   18018          74 :     query = createPQExpBuffer();
   18019          74 :     delqry = createPQExpBuffer();
   18020             : 
   18021          74 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   18022             : 
   18023          74 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   18024          74 :     appendPQExpBufferStr(query, qevtname);
   18025          74 :     appendPQExpBufferStr(query, " ON ");
   18026          74 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   18027             : 
   18028          74 :     if (strcmp("", evtinfo->evttags) != 0)
   18029             :     {
   18030          10 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   18031          10 :         appendPQExpBufferStr(query, evtinfo->evttags);
   18032          10 :         appendPQExpBufferChar(query, ')');
   18033             :     }
   18034             : 
   18035          74 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   18036          74 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   18037          74 :     appendPQExpBufferStr(query, "();\n");
   18038             : 
   18039          74 :     if (evtinfo->evtenabled != 'O')
   18040             :     {
   18041           0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   18042             :                           qevtname);
   18043           0 :         switch (evtinfo->evtenabled)
   18044             :         {
   18045           0 :             case 'D':
   18046           0 :                 appendPQExpBufferStr(query, "DISABLE");
   18047           0 :                 break;
   18048           0 :             case 'A':
   18049           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18050           0 :                 break;
   18051           0 :             case 'R':
   18052           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18053           0 :                 break;
   18054           0 :             default:
   18055           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18056           0 :                 break;
   18057             :         }
   18058           0 :         appendPQExpBufferStr(query, ";\n");
   18059             :     }
   18060             : 
   18061          74 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   18062             :                       qevtname);
   18063             : 
   18064          74 :     if (dopt->binary_upgrade)
   18065           4 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   18066             :                                         "EVENT TRIGGER", qevtname, NULL);
   18067             : 
   18068          74 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18069          74 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   18070          74 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   18071             :                                   .owner = evtinfo->evtowner,
   18072             :                                   .description = "EVENT TRIGGER",
   18073             :                                   .section = SECTION_POST_DATA,
   18074             :                                   .createStmt = query->data,
   18075             :                                   .dropStmt = delqry->data));
   18076             : 
   18077          74 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18078           0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   18079             :                     NULL, evtinfo->evtowner,
   18080             :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   18081             : 
   18082          74 :     destroyPQExpBuffer(query);
   18083          74 :     destroyPQExpBuffer(delqry);
   18084          74 :     free(qevtname);
   18085             : }
   18086             : 
   18087             : /*
   18088             :  * dumpRule
   18089             :  *      Dump a rule
   18090             :  */
   18091             : static void
   18092        1820 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   18093             : {
   18094        1820 :     DumpOptions *dopt = fout->dopt;
   18095        1820 :     TableInfo  *tbinfo = rinfo->ruletable;
   18096             :     bool        is_view;
   18097             :     PQExpBuffer query;
   18098             :     PQExpBuffer cmd;
   18099             :     PQExpBuffer delcmd;
   18100             :     PQExpBuffer ruleprefix;
   18101             :     char       *qtabname;
   18102             :     PGresult   *res;
   18103             :     char       *tag;
   18104             : 
   18105             :     /* Do nothing in data-only dump */
   18106        1820 :     if (dopt->dataOnly)
   18107          60 :         return;
   18108             : 
   18109             :     /*
   18110             :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   18111             :      * we do not want to dump it as a separate object.
   18112             :      */
   18113        1760 :     if (!rinfo->separate)
   18114        1346 :         return;
   18115             : 
   18116             :     /*
   18117             :      * If it's an ON SELECT rule, we want to print it as a view definition,
   18118             :      * instead of a rule.
   18119             :      */
   18120         414 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   18121             : 
   18122         414 :     query = createPQExpBuffer();
   18123         414 :     cmd = createPQExpBuffer();
   18124         414 :     delcmd = createPQExpBuffer();
   18125         414 :     ruleprefix = createPQExpBuffer();
   18126             : 
   18127         414 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18128             : 
   18129         414 :     if (is_view)
   18130             :     {
   18131             :         PQExpBuffer result;
   18132             : 
   18133             :         /*
   18134             :          * We need OR REPLACE here because we'll be replacing a dummy view.
   18135             :          * Otherwise this should look largely like the regular view dump code.
   18136             :          */
   18137          20 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   18138          20 :                           fmtQualifiedDumpable(tbinfo));
   18139          20 :         if (nonemptyReloptions(tbinfo->reloptions))
   18140             :         {
   18141           0 :             appendPQExpBufferStr(cmd, " WITH (");
   18142           0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   18143           0 :             appendPQExpBufferChar(cmd, ')');
   18144             :         }
   18145          20 :         result = createViewAsClause(fout, tbinfo);
   18146          20 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   18147          20 :         destroyPQExpBuffer(result);
   18148          20 :         if (tbinfo->checkoption != NULL)
   18149           0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   18150             :                               tbinfo->checkoption);
   18151          20 :         appendPQExpBufferStr(cmd, ";\n");
   18152             :     }
   18153             :     else
   18154             :     {
   18155             :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   18156         394 :         appendPQExpBuffer(query,
   18157             :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   18158             :                           rinfo->dobj.catId.oid);
   18159             : 
   18160         394 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18161             : 
   18162         394 :         if (PQntuples(res) != 1)
   18163           0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   18164             :                      rinfo->dobj.name, tbinfo->dobj.name);
   18165             : 
   18166         394 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   18167             : 
   18168         394 :         PQclear(res);
   18169             :     }
   18170             : 
   18171             :     /*
   18172             :      * Add the command to alter the rules replication firing semantics if it
   18173             :      * differs from the default.
   18174             :      */
   18175         414 :     if (rinfo->ev_enabled != 'O')
   18176             :     {
   18177          30 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   18178          30 :         switch (rinfo->ev_enabled)
   18179             :         {
   18180           0 :             case 'A':
   18181           0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   18182           0 :                                   fmtId(rinfo->dobj.name));
   18183           0 :                 break;
   18184           0 :             case 'R':
   18185           0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   18186           0 :                                   fmtId(rinfo->dobj.name));
   18187           0 :                 break;
   18188          30 :             case 'D':
   18189          30 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   18190          30 :                                   fmtId(rinfo->dobj.name));
   18191          30 :                 break;
   18192             :         }
   18193         384 :     }
   18194             : 
   18195         414 :     if (is_view)
   18196             :     {
   18197             :         /*
   18198             :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   18199             :          * REPLACE VIEW to replace the rule with something with minimal
   18200             :          * dependencies.
   18201             :          */
   18202             :         PQExpBuffer result;
   18203             : 
   18204          20 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   18205          20 :                           fmtQualifiedDumpable(tbinfo));
   18206          20 :         result = createDummyViewAsClause(fout, tbinfo);
   18207          20 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   18208          20 :         destroyPQExpBuffer(result);
   18209             :     }
   18210             :     else
   18211             :     {
   18212         394 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   18213         394 :                           fmtId(rinfo->dobj.name));
   18214         394 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   18215         394 :                           fmtQualifiedDumpable(tbinfo));
   18216             :     }
   18217             : 
   18218         414 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   18219         414 :                       fmtId(rinfo->dobj.name));
   18220             : 
   18221         414 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   18222             : 
   18223         414 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18224         414 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   18225         414 :                      ARCHIVE_OPTS(.tag = tag,
   18226             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18227             :                                   .owner = tbinfo->rolname,
   18228             :                                   .description = "RULE",
   18229             :                                   .section = SECTION_POST_DATA,
   18230             :                                   .createStmt = cmd->data,
   18231             :                                   .dropStmt = delcmd->data));
   18232             : 
   18233             :     /* Dump rule comments */
   18234         414 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18235           0 :         dumpComment(fout, ruleprefix->data, qtabname,
   18236           0 :                     tbinfo->dobj.namespace->dobj.name,
   18237             :                     tbinfo->rolname,
   18238             :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   18239             : 
   18240         414 :     free(tag);
   18241         414 :     destroyPQExpBuffer(query);
   18242         414 :     destroyPQExpBuffer(cmd);
   18243         414 :     destroyPQExpBuffer(delcmd);
   18244         414 :     destroyPQExpBuffer(ruleprefix);
   18245         414 :     free(qtabname);
   18246             : }
   18247             : 
   18248             : /*
   18249             :  * getExtensionMembership --- obtain extension membership data
   18250             :  *
   18251             :  * We need to identify objects that are extension members as soon as they're
   18252             :  * loaded, so that we can correctly determine whether they need to be dumped.
   18253             :  * Generally speaking, extension member objects will get marked as *not* to
   18254             :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   18255             :  * command.  However, in binary upgrade mode we still need to dump the members
   18256             :  * individually.
   18257             :  */
   18258             : void
   18259         306 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   18260             :                        int numExtensions)
   18261             : {
   18262             :     PQExpBuffer query;
   18263             :     PGresult   *res;
   18264             :     int         ntups,
   18265             :                 i;
   18266             :     int         i_classid,
   18267             :                 i_objid,
   18268             :                 i_refobjid;
   18269             :     ExtensionInfo *ext;
   18270             : 
   18271             :     /* Nothing to do if no extensions */
   18272         306 :     if (numExtensions == 0)
   18273           0 :         return;
   18274             : 
   18275         306 :     query = createPQExpBuffer();
   18276             : 
   18277             :     /* refclassid constraint is redundant but may speed the search */
   18278         306 :     appendPQExpBufferStr(query, "SELECT "
   18279             :                          "classid, objid, refobjid "
   18280             :                          "FROM pg_depend "
   18281             :                          "WHERE refclassid = 'pg_extension'::regclass "
   18282             :                          "AND deptype = 'e' "
   18283             :                          "ORDER BY 3");
   18284             : 
   18285         306 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18286             : 
   18287         306 :     ntups = PQntuples(res);
   18288             : 
   18289         306 :     i_classid = PQfnumber(res, "classid");
   18290         306 :     i_objid = PQfnumber(res, "objid");
   18291         306 :     i_refobjid = PQfnumber(res, "refobjid");
   18292             : 
   18293             :     /*
   18294             :      * Since we ordered the SELECT by referenced ID, we can expect that
   18295             :      * multiple entries for the same extension will appear together; this
   18296             :      * saves on searches.
   18297             :      */
   18298         306 :     ext = NULL;
   18299             : 
   18300        2730 :     for (i = 0; i < ntups; i++)
   18301             :     {
   18302             :         CatalogId   objId;
   18303             :         Oid         extId;
   18304             : 
   18305        2424 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   18306        2424 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   18307        2424 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   18308             : 
   18309        2424 :         if (ext == NULL ||
   18310        2118 :             ext->dobj.catId.oid != extId)
   18311         356 :             ext = findExtensionByOid(extId);
   18312             : 
   18313        2424 :         if (ext == NULL)
   18314             :         {
   18315             :             /* shouldn't happen */
   18316           0 :             pg_log_warning("could not find referenced extension %u", extId);
   18317           0 :             continue;
   18318             :         }
   18319             : 
   18320        2424 :         recordExtensionMembership(objId, ext);
   18321             :     }
   18322             : 
   18323         306 :     PQclear(res);
   18324             : 
   18325         306 :     destroyPQExpBuffer(query);
   18326             : }
   18327             : 
   18328             : /*
   18329             :  * processExtensionTables --- deal with extension configuration tables
   18330             :  *
   18331             :  * There are two parts to this process:
   18332             :  *
   18333             :  * 1. Identify and create dump records for extension configuration tables.
   18334             :  *
   18335             :  *    Extensions can mark tables as "configuration", which means that the user
   18336             :  *    is able and expected to modify those tables after the extension has been
   18337             :  *    loaded.  For these tables, we dump out only the data- the structure is
   18338             :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   18339             :  *    foreign keys, which brings us to-
   18340             :  *
   18341             :  * 2. Record FK dependencies between configuration tables.
   18342             :  *
   18343             :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   18344             :  *    the data is loaded, we have to work out what the best order for reloading
   18345             :  *    the data is, to avoid FK violations when the tables are restored.  This is
   18346             :  *    not perfect- we can't handle circular dependencies and if any exist they
   18347             :  *    will cause an invalid dump to be produced (though at least all of the data
   18348             :  *    is included for a user to manually restore).  This is currently documented
   18349             :  *    but perhaps we can provide a better solution in the future.
   18350             :  */
   18351             : void
   18352         304 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   18353             :                        int numExtensions)
   18354             : {
   18355         304 :     DumpOptions *dopt = fout->dopt;
   18356             :     PQExpBuffer query;
   18357             :     PGresult   *res;
   18358             :     int         ntups,
   18359             :                 i;
   18360             :     int         i_conrelid,
   18361             :                 i_confrelid;
   18362             : 
   18363             :     /* Nothing to do if no extensions */
   18364         304 :     if (numExtensions == 0)
   18365           0 :         return;
   18366             : 
   18367             :     /*
   18368             :      * Identify extension configuration tables and create TableDataInfo
   18369             :      * objects for them, ensuring their data will be dumped even though the
   18370             :      * tables themselves won't be.
   18371             :      *
   18372             :      * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
   18373             :      * user data in a configuration table is treated like schema data. This
   18374             :      * seems appropriate since system data in a config table would get
   18375             :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   18376             :      * list of extensions to be included, none of its data is dumped.
   18377             :      */
   18378         658 :     for (i = 0; i < numExtensions; i++)
   18379             :     {
   18380         354 :         ExtensionInfo *curext = &(extinfo[i]);
   18381         354 :         char       *extconfig = curext->extconfig;
   18382         354 :         char       *extcondition = curext->extcondition;
   18383         354 :         char      **extconfigarray = NULL;
   18384         354 :         char      **extconditionarray = NULL;
   18385         354 :         int         nconfigitems = 0;
   18386         354 :         int         nconditionitems = 0;
   18387             : 
   18388             :         /*
   18389             :          * Check if this extension is listed as to include in the dump.  If
   18390             :          * not, any table data associated with it is discarded.
   18391             :          */
   18392         354 :         if (extension_include_oids.head != NULL &&
   18393          16 :             !simple_oid_list_member(&extension_include_oids,
   18394             :                                     curext->dobj.catId.oid))
   18395          12 :             continue;
   18396             : 
   18397             :         /*
   18398             :          * Check if this extension is listed as to exclude in the dump.  If
   18399             :          * yes, any table data associated with it is discarded.
   18400             :          */
   18401         354 :         if (extension_exclude_oids.head != NULL &&
   18402           8 :             simple_oid_list_member(&extension_exclude_oids,
   18403             :                                    curext->dobj.catId.oid))
   18404           4 :             continue;
   18405             : 
   18406         342 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   18407             :         {
   18408             :             int         j;
   18409             : 
   18410          40 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   18411           0 :                 pg_fatal("could not parse %s array", "extconfig");
   18412          40 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   18413           0 :                 pg_fatal("could not parse %s array", "extcondition");
   18414          40 :             if (nconfigitems != nconditionitems)
   18415           0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   18416             : 
   18417         120 :             for (j = 0; j < nconfigitems; j++)
   18418             :             {
   18419             :                 TableInfo  *configtbl;
   18420          80 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   18421          80 :                 bool        dumpobj =
   18422          80 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   18423             : 
   18424          80 :                 configtbl = findTableByOid(configtbloid);
   18425          80 :                 if (configtbl == NULL)
   18426           0 :                     continue;
   18427             : 
   18428             :                 /*
   18429             :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   18430             :                  * unless the table or its schema is explicitly included
   18431             :                  */
   18432          80 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   18433             :                 {
   18434             :                     /* check table explicitly requested */
   18435           4 :                     if (table_include_oids.head != NULL &&
   18436           0 :                         simple_oid_list_member(&table_include_oids,
   18437             :                                                configtbloid))
   18438           0 :                         dumpobj = true;
   18439             : 
   18440             :                     /* check table's schema explicitly requested */
   18441           4 :                     if (configtbl->dobj.namespace->dobj.dump &
   18442             :                         DUMP_COMPONENT_DATA)
   18443           4 :                         dumpobj = true;
   18444             :                 }
   18445             : 
   18446             :                 /* check table excluded by an exclusion switch */
   18447          88 :                 if (table_exclude_oids.head != NULL &&
   18448           8 :                     simple_oid_list_member(&table_exclude_oids,
   18449             :                                            configtbloid))
   18450           2 :                     dumpobj = false;
   18451             : 
   18452             :                 /* check schema excluded by an exclusion switch */
   18453          80 :                 if (simple_oid_list_member(&schema_exclude_oids,
   18454          80 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   18455           0 :                     dumpobj = false;
   18456             : 
   18457          80 :                 if (dumpobj)
   18458             :                 {
   18459          78 :                     makeTableDataInfo(dopt, configtbl);
   18460          78 :                     if (configtbl->dataObj != NULL)
   18461             :                     {
   18462          78 :                         if (strlen(extconditionarray[j]) > 0)
   18463           0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   18464             :                     }
   18465             :                 }
   18466             :             }
   18467             :         }
   18468         342 :         if (extconfigarray)
   18469          40 :             free(extconfigarray);
   18470         342 :         if (extconditionarray)
   18471          40 :             free(extconditionarray);
   18472             :     }
   18473             : 
   18474             :     /*
   18475             :      * Now that all the TableDataInfo objects have been created for all the
   18476             :      * extensions, check their FK dependencies and register them to try and
   18477             :      * dump the data out in an order that they can be restored in.
   18478             :      *
   18479             :      * Note that this is not a problem for user tables as their FKs are
   18480             :      * recreated after the data has been loaded.
   18481             :      */
   18482             : 
   18483         304 :     query = createPQExpBuffer();
   18484             : 
   18485         304 :     printfPQExpBuffer(query,
   18486             :                       "SELECT conrelid, confrelid "
   18487             :                       "FROM pg_constraint "
   18488             :                       "JOIN pg_depend ON (objid = confrelid) "
   18489             :                       "WHERE contype = 'f' "
   18490             :                       "AND refclassid = 'pg_extension'::regclass "
   18491             :                       "AND classid = 'pg_class'::regclass;");
   18492             : 
   18493         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18494         304 :     ntups = PQntuples(res);
   18495             : 
   18496         304 :     i_conrelid = PQfnumber(res, "conrelid");
   18497         304 :     i_confrelid = PQfnumber(res, "confrelid");
   18498             : 
   18499             :     /* Now get the dependencies and register them */
   18500         304 :     for (i = 0; i < ntups; i++)
   18501             :     {
   18502             :         Oid         conrelid,
   18503             :                     confrelid;
   18504             :         TableInfo  *reftable,
   18505             :                    *contable;
   18506             : 
   18507           0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   18508           0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   18509           0 :         contable = findTableByOid(conrelid);
   18510           0 :         reftable = findTableByOid(confrelid);
   18511             : 
   18512           0 :         if (reftable == NULL ||
   18513           0 :             reftable->dataObj == NULL ||
   18514           0 :             contable == NULL ||
   18515           0 :             contable->dataObj == NULL)
   18516           0 :             continue;
   18517             : 
   18518             :         /*
   18519             :          * Make referencing TABLE_DATA object depend on the referenced table's
   18520             :          * TABLE_DATA object.
   18521             :          */
   18522           0 :         addObjectDependency(&contable->dataObj->dobj,
   18523           0 :                             reftable->dataObj->dobj.dumpId);
   18524             :     }
   18525         304 :     PQclear(res);
   18526         304 :     destroyPQExpBuffer(query);
   18527             : }
   18528             : 
   18529             : /*
   18530             :  * getDependencies --- obtain available dependency data
   18531             :  */
   18532             : static void
   18533         304 : getDependencies(Archive *fout)
   18534             : {
   18535             :     PQExpBuffer query;
   18536             :     PGresult   *res;
   18537             :     int         ntups,
   18538             :                 i;
   18539             :     int         i_classid,
   18540             :                 i_objid,
   18541             :                 i_refclassid,
   18542             :                 i_refobjid,
   18543             :                 i_deptype;
   18544             :     DumpableObject *dobj,
   18545             :                *refdobj;
   18546             : 
   18547         304 :     pg_log_info("reading dependency data");
   18548             : 
   18549         304 :     query = createPQExpBuffer();
   18550             : 
   18551             :     /*
   18552             :      * Messy query to collect the dependency data we need.  Note that we
   18553             :      * ignore the sub-object column, so that dependencies of or on a column
   18554             :      * look the same as dependencies of or on a whole table.
   18555             :      *
   18556             :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   18557             :      * already processed by getExtensionMembership.
   18558             :      */
   18559         304 :     appendPQExpBufferStr(query, "SELECT "
   18560             :                          "classid, objid, refclassid, refobjid, deptype "
   18561             :                          "FROM pg_depend "
   18562             :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   18563             : 
   18564             :     /*
   18565             :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   18566             :      * have to translate their dependencies into dependencies of their parent
   18567             :      * opfamily.  Ignore internal dependencies though, as those will point to
   18568             :      * their parent opclass, which we needn't consider here (and if we did,
   18569             :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   18570             :      * entries will have dependencies on their parent opfamily, which we
   18571             :      * should drop since they'd likewise become useless self-dependencies.
   18572             :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   18573             :      */
   18574         304 :     appendPQExpBufferStr(query, "UNION ALL\n"
   18575             :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   18576             :                          "FROM pg_depend d, pg_amop o "
   18577             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   18578             :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   18579             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   18580             : 
   18581             :     /* Likewise for pg_amproc entries */
   18582         304 :     appendPQExpBufferStr(query, "UNION ALL\n"
   18583             :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   18584             :                          "FROM pg_depend d, pg_amproc p "
   18585             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   18586             :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   18587             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   18588             : 
   18589             :     /* Sort the output for efficiency below */
   18590         304 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   18591             : 
   18592         304 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18593             : 
   18594         304 :     ntups = PQntuples(res);
   18595             : 
   18596         304 :     i_classid = PQfnumber(res, "classid");
   18597         304 :     i_objid = PQfnumber(res, "objid");
   18598         304 :     i_refclassid = PQfnumber(res, "refclassid");
   18599         304 :     i_refobjid = PQfnumber(res, "refobjid");
   18600         304 :     i_deptype = PQfnumber(res, "deptype");
   18601             : 
   18602             :     /*
   18603             :      * Since we ordered the SELECT by referencing ID, we can expect that
   18604             :      * multiple entries for the same object will appear together; this saves
   18605             :      * on searches.
   18606             :      */
   18607         304 :     dobj = NULL;
   18608             : 
   18609      633686 :     for (i = 0; i < ntups; i++)
   18610             :     {
   18611             :         CatalogId   objId;
   18612             :         CatalogId   refobjId;
   18613             :         char        deptype;
   18614             : 
   18615      633382 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   18616      633382 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   18617      633382 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   18618      633382 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   18619      633382 :         deptype = *(PQgetvalue(res, i, i_deptype));
   18620             : 
   18621      633382 :         if (dobj == NULL ||
   18622      600382 :             dobj->catId.tableoid != objId.tableoid ||
   18623      596806 :             dobj->catId.oid != objId.oid)
   18624      269376 :             dobj = findObjectByCatalogId(objId);
   18625             : 
   18626             :         /*
   18627             :          * Failure to find objects mentioned in pg_depend is not unexpected,
   18628             :          * since for example we don't collect info about TOAST tables.
   18629             :          */
   18630      633382 :         if (dobj == NULL)
   18631             :         {
   18632             : #ifdef NOT_USED
   18633             :             pg_log_warning("no referencing object %u %u",
   18634             :                            objId.tableoid, objId.oid);
   18635             : #endif
   18636       34198 :             continue;
   18637             :         }
   18638             : 
   18639      600670 :         refdobj = findObjectByCatalogId(refobjId);
   18640             : 
   18641      600670 :         if (refdobj == NULL)
   18642             :         {
   18643             : #ifdef NOT_USED
   18644             :             pg_log_warning("no referenced object %u %u",
   18645             :                            refobjId.tableoid, refobjId.oid);
   18646             : #endif
   18647        1486 :             continue;
   18648             :         }
   18649             : 
   18650             :         /*
   18651             :          * For 'x' dependencies, mark the object for later; we still add the
   18652             :          * normal dependency, for possible ordering purposes.  Currently
   18653             :          * pg_dump_sort.c knows to put extensions ahead of all object types
   18654             :          * that could possibly depend on them, but this is safer.
   18655             :          */
   18656      599184 :         if (deptype == 'x')
   18657          88 :             dobj->depends_on_ext = true;
   18658             : 
   18659             :         /*
   18660             :          * Ordinarily, table rowtypes have implicit dependencies on their
   18661             :          * tables.  However, for a composite type the implicit dependency goes
   18662             :          * the other way in pg_depend; which is the right thing for DROP but
   18663             :          * it doesn't produce the dependency ordering we need. So in that one
   18664             :          * case, we reverse the direction of the dependency.
   18665             :          */
   18666      599184 :         if (deptype == 'i' &&
   18667      164788 :             dobj->objType == DO_TABLE &&
   18668        1758 :             refdobj->objType == DO_TYPE)
   18669         296 :             addObjectDependency(refdobj, dobj->dumpId);
   18670             :         else
   18671             :             /* normal case */
   18672      598888 :             addObjectDependency(dobj, refdobj->dumpId);
   18673             :     }
   18674             : 
   18675         304 :     PQclear(res);
   18676             : 
   18677         304 :     destroyPQExpBuffer(query);
   18678         304 : }
   18679             : 
   18680             : 
   18681             : /*
   18682             :  * createBoundaryObjects - create dummy DumpableObjects to represent
   18683             :  * dump section boundaries.
   18684             :  */
   18685             : static DumpableObject *
   18686         304 : createBoundaryObjects(void)
   18687             : {
   18688             :     DumpableObject *dobjs;
   18689             : 
   18690         304 :     dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
   18691             : 
   18692         304 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   18693         304 :     dobjs[0].catId = nilCatalogId;
   18694         304 :     AssignDumpId(dobjs + 0);
   18695         304 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   18696             : 
   18697         304 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   18698         304 :     dobjs[1].catId = nilCatalogId;
   18699         304 :     AssignDumpId(dobjs + 1);
   18700         304 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   18701             : 
   18702         304 :     return dobjs;
   18703             : }
   18704             : 
   18705             : /*
   18706             :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   18707             :  * section boundaries.
   18708             :  */
   18709             : static void
   18710         304 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   18711             :                         DumpableObject *boundaryObjs)
   18712             : {
   18713         304 :     DumpableObject *preDataBound = boundaryObjs + 0;
   18714         304 :     DumpableObject *postDataBound = boundaryObjs + 1;
   18715             :     int         i;
   18716             : 
   18717     1098608 :     for (i = 0; i < numObjs; i++)
   18718             :     {
   18719     1098304 :         DumpableObject *dobj = dobjs[i];
   18720             : 
   18721             :         /*
   18722             :          * The classification of object types here must match the SECTION_xxx
   18723             :          * values assigned during subsequent ArchiveEntry calls!
   18724             :          */
   18725     1098304 :         switch (dobj->objType)
   18726             :         {
   18727     1030214 :             case DO_NAMESPACE:
   18728             :             case DO_EXTENSION:
   18729             :             case DO_TYPE:
   18730             :             case DO_SHELL_TYPE:
   18731             :             case DO_FUNC:
   18732             :             case DO_AGG:
   18733             :             case DO_OPERATOR:
   18734             :             case DO_ACCESS_METHOD:
   18735             :             case DO_OPCLASS:
   18736             :             case DO_OPFAMILY:
   18737             :             case DO_COLLATION:
   18738             :             case DO_CONVERSION:
   18739             :             case DO_TABLE:
   18740             :             case DO_TABLE_ATTACH:
   18741             :             case DO_ATTRDEF:
   18742             :             case DO_PROCLANG:
   18743             :             case DO_CAST:
   18744             :             case DO_DUMMY_TYPE:
   18745             :             case DO_TSPARSER:
   18746             :             case DO_TSDICT:
   18747             :             case DO_TSTEMPLATE:
   18748             :             case DO_TSCONFIG:
   18749             :             case DO_FDW:
   18750             :             case DO_FOREIGN_SERVER:
   18751             :             case DO_TRANSFORM:
   18752             :                 /* Pre-data objects: must come before the pre-data boundary */
   18753     1030214 :                 addObjectDependency(preDataBound, dobj->dumpId);
   18754     1030214 :                 break;
   18755        8038 :             case DO_TABLE_DATA:
   18756             :             case DO_SEQUENCE_SET:
   18757             :             case DO_LARGE_OBJECT:
   18758             :             case DO_LARGE_OBJECT_DATA:
   18759             :                 /* Data objects: must come between the boundaries */
   18760        8038 :                 addObjectDependency(dobj, preDataBound->dumpId);
   18761        8038 :                 addObjectDependency(postDataBound, dobj->dumpId);
   18762        8038 :                 break;
   18763        9632 :             case DO_INDEX:
   18764             :             case DO_INDEX_ATTACH:
   18765             :             case DO_STATSEXT:
   18766             :             case DO_REFRESH_MATVIEW:
   18767             :             case DO_TRIGGER:
   18768             :             case DO_EVENT_TRIGGER:
   18769             :             case DO_DEFAULT_ACL:
   18770             :             case DO_POLICY:
   18771             :             case DO_PUBLICATION:
   18772             :             case DO_PUBLICATION_REL:
   18773             :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   18774             :             case DO_SUBSCRIPTION:
   18775             :             case DO_SUBSCRIPTION_REL:
   18776             :                 /* Post-data objects: must come after the post-data boundary */
   18777        9632 :                 addObjectDependency(dobj, postDataBound->dumpId);
   18778        9632 :                 break;
   18779       45880 :             case DO_RULE:
   18780             :                 /* Rules are post-data, but only if dumped separately */
   18781       45880 :                 if (((RuleInfo *) dobj)->separate)
   18782         998 :                     addObjectDependency(dobj, postDataBound->dumpId);
   18783       45880 :                 break;
   18784        3932 :             case DO_CONSTRAINT:
   18785             :             case DO_FK_CONSTRAINT:
   18786             :                 /* Constraints are post-data, but only if dumped separately */
   18787        3932 :                 if (((ConstraintInfo *) dobj)->separate)
   18788        2734 :                     addObjectDependency(dobj, postDataBound->dumpId);
   18789        3932 :                 break;
   18790         304 :             case DO_PRE_DATA_BOUNDARY:
   18791             :                 /* nothing to do */
   18792         304 :                 break;
   18793         304 :             case DO_POST_DATA_BOUNDARY:
   18794             :                 /* must come after the pre-data boundary */
   18795         304 :                 addObjectDependency(dobj, preDataBound->dumpId);
   18796         304 :                 break;
   18797             :         }
   18798     1098304 :     }
   18799         304 : }
   18800             : 
   18801             : 
   18802             : /*
   18803             :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   18804             :  *
   18805             :  * The raw dependency data obtained by getDependencies() is not terribly
   18806             :  * useful in an archive dump, because in many cases there are dependency
   18807             :  * chains linking through objects that don't appear explicitly in the dump.
   18808             :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   18809             :  * will depend on other objects --- but the rule will not appear as a separate
   18810             :  * object in the dump.  We need to adjust the view's dependencies to include
   18811             :  * whatever the rule depends on that is included in the dump.
   18812             :  *
   18813             :  * Just to make things more complicated, there are also "special" dependencies
   18814             :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   18815             :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   18816             :  * its table.  In these cases we must leave the dependencies strictly as-is
   18817             :  * even if they refer to not-to-be-dumped objects.
   18818             :  *
   18819             :  * To handle this, the convention is that "special" dependencies are created
   18820             :  * during ArchiveEntry calls, and an archive TOC item that has any such
   18821             :  * entries will not be touched here.  Otherwise, we recursively search the
   18822             :  * DumpableObject data structures to build the correct dependencies for each
   18823             :  * archive TOC item.
   18824             :  */
   18825             : static void
   18826          62 : BuildArchiveDependencies(Archive *fout)
   18827             : {
   18828          62 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   18829             :     TocEntry   *te;
   18830             : 
   18831             :     /* Scan all TOC entries in the archive */
   18832        9658 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   18833             :     {
   18834             :         DumpableObject *dobj;
   18835             :         DumpId     *dependencies;
   18836             :         int         nDeps;
   18837             :         int         allocDeps;
   18838             : 
   18839             :         /* No need to process entries that will not be dumped */
   18840        9596 :         if (te->reqs == 0)
   18841        2950 :             continue;
   18842             :         /* Ignore entries that already have "special" dependencies */
   18843        9590 :         if (te->nDeps > 0)
   18844        2418 :             continue;
   18845             :         /* Otherwise, look up the item's original DumpableObject, if any */
   18846        7172 :         dobj = findObjectByDumpId(te->dumpId);
   18847        7172 :         if (dobj == NULL)
   18848         318 :             continue;
   18849             :         /* No work if it has no dependencies */
   18850        6854 :         if (dobj->nDeps <= 0)
   18851         208 :             continue;
   18852             :         /* Set up work array */
   18853        6646 :         allocDeps = 64;
   18854        6646 :         dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
   18855        6646 :         nDeps = 0;
   18856             :         /* Recursively find all dumpable dependencies */
   18857        6646 :         findDumpableDependencies(AH, dobj,
   18858             :                                  &dependencies, &nDeps, &allocDeps);
   18859             :         /* And save 'em ... */
   18860        6646 :         if (nDeps > 0)
   18861             :         {
   18862        5026 :             dependencies = (DumpId *) pg_realloc(dependencies,
   18863             :                                                  nDeps * sizeof(DumpId));
   18864        5026 :             te->dependencies = dependencies;
   18865        5026 :             te->nDeps = nDeps;
   18866             :         }
   18867             :         else
   18868        1620 :             free(dependencies);
   18869             :     }
   18870          62 : }
   18871             : 
   18872             : /* Recursive search subroutine for BuildArchiveDependencies */
   18873             : static void
   18874       16392 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   18875             :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   18876             : {
   18877             :     int         i;
   18878             : 
   18879             :     /*
   18880             :      * Ignore section boundary objects: if we search through them, we'll
   18881             :      * report lots of bogus dependencies.
   18882             :      */
   18883       16392 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   18884       16354 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   18885        2896 :         return;
   18886             : 
   18887       34114 :     for (i = 0; i < dobj->nDeps; i++)
   18888             :     {
   18889       20618 :         DumpId      depid = dobj->dependencies[i];
   18890             : 
   18891       20618 :         if (TocIDRequired(AH, depid) != 0)
   18892             :         {
   18893             :             /* Object will be dumped, so just reference it as a dependency */
   18894       10872 :             if (*nDeps >= *allocDeps)
   18895             :             {
   18896           0 :                 *allocDeps *= 2;
   18897           0 :                 *dependencies = (DumpId *) pg_realloc(*dependencies,
   18898           0 :                                                       *allocDeps * sizeof(DumpId));
   18899             :             }
   18900       10872 :             (*dependencies)[*nDeps] = depid;
   18901       10872 :             (*nDeps)++;
   18902             :         }
   18903             :         else
   18904             :         {
   18905             :             /*
   18906             :              * Object will not be dumped, so recursively consider its deps. We
   18907             :              * rely on the assumption that sortDumpableObjects already broke
   18908             :              * any dependency loops, else we might recurse infinitely.
   18909             :              */
   18910        9746 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   18911             : 
   18912        9746 :             if (otherdobj)
   18913        9746 :                 findDumpableDependencies(AH, otherdobj,
   18914             :                                          dependencies, nDeps, allocDeps);
   18915             :         }
   18916             :     }
   18917             : }
   18918             : 
   18919             : 
   18920             : /*
   18921             :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   18922             :  * given type OID.
   18923             :  *
   18924             :  * This does not guarantee to schema-qualify the output, so it should not
   18925             :  * be used to create the target object name for CREATE or ALTER commands.
   18926             :  *
   18927             :  * Note that the result is cached and must not be freed by the caller.
   18928             :  */
   18929             : static const char *
   18930        4548 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   18931             : {
   18932             :     TypeInfo   *typeInfo;
   18933             :     char       *result;
   18934             :     PQExpBuffer query;
   18935             :     PGresult   *res;
   18936             : 
   18937        4548 :     if (oid == 0)
   18938             :     {
   18939           0 :         if ((opts & zeroAsStar) != 0)
   18940           0 :             return "*";
   18941           0 :         else if ((opts & zeroAsNone) != 0)
   18942           0 :             return "NONE";
   18943             :     }
   18944             : 
   18945             :     /* see if we have the result cached in the type's TypeInfo record */
   18946        4548 :     typeInfo = findTypeByOid(oid);
   18947        4548 :     if (typeInfo && typeInfo->ftypname)
   18948        3624 :         return typeInfo->ftypname;
   18949             : 
   18950         924 :     query = createPQExpBuffer();
   18951         924 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   18952             :                       oid);
   18953             : 
   18954         924 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   18955             : 
   18956             :     /* result of format_type is already quoted */
   18957         924 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   18958             : 
   18959         924 :     PQclear(res);
   18960         924 :     destroyPQExpBuffer(query);
   18961             : 
   18962             :     /*
   18963             :      * Cache the result for re-use in later requests, if possible.  If we
   18964             :      * don't have a TypeInfo for the type, the string will be leaked once the
   18965             :      * caller is done with it ... but that case really should not happen, so
   18966             :      * leaking if it does seems acceptable.
   18967             :      */
   18968         924 :     if (typeInfo)
   18969         924 :         typeInfo->ftypname = result;
   18970             : 
   18971         924 :     return result;
   18972             : }
   18973             : 
   18974             : /*
   18975             :  * Return a column list clause for the given relation.
   18976             :  *
   18977             :  * Special case: if there are no undropped columns in the relation, return
   18978             :  * "", not an invalid "()" column list.
   18979             :  */
   18980             : static const char *
   18981       13636 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   18982             : {
   18983       13636 :     int         numatts = ti->numatts;
   18984       13636 :     char      **attnames = ti->attnames;
   18985       13636 :     bool       *attisdropped = ti->attisdropped;
   18986       13636 :     char       *attgenerated = ti->attgenerated;
   18987             :     bool        needComma;
   18988             :     int         i;
   18989             : 
   18990       13636 :     appendPQExpBufferChar(buffer, '(');
   18991       13636 :     needComma = false;
   18992       67224 :     for (i = 0; i < numatts; i++)
   18993             :     {
   18994       53588 :         if (attisdropped[i])
   18995        1132 :             continue;
   18996       52456 :         if (attgenerated[i])
   18997        1180 :             continue;
   18998       51276 :         if (needComma)
   18999       38072 :             appendPQExpBufferStr(buffer, ", ");
   19000       51276 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   19001       51276 :         needComma = true;
   19002             :     }
   19003             : 
   19004       13636 :     if (!needComma)
   19005         432 :         return "";                /* no undropped columns */
   19006             : 
   19007       13204 :     appendPQExpBufferChar(buffer, ')');
   19008       13204 :     return buffer->data;
   19009             : }
   19010             : 
   19011             : /*
   19012             :  * Check if a reloptions array is nonempty.
   19013             :  */
   19014             : static bool
   19015       22896 : nonemptyReloptions(const char *reloptions)
   19016             : {
   19017             :     /* Don't want to print it if it's just "{}" */
   19018       22896 :     return (reloptions != NULL && strlen(reloptions) > 2);
   19019             : }
   19020             : 
   19021             : /*
   19022             :  * Format a reloptions array and append it to the given buffer.
   19023             :  *
   19024             :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   19025             :  */
   19026             : static void
   19027         408 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   19028             :                         const char *prefix, Archive *fout)
   19029             : {
   19030             :     bool        res;
   19031             : 
   19032         408 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   19033         408 :                                 fout->std_strings);
   19034         408 :     if (!res)
   19035           0 :         pg_log_warning("could not parse %s array", "reloptions");
   19036         408 : }
   19037             : 
   19038             : /*
   19039             :  * read_dump_filters - retrieve object identifier patterns from file
   19040             :  *
   19041             :  * Parse the specified filter file for include and exclude patterns, and add
   19042             :  * them to the relevant lists.  If the filename is "-" then filters will be
   19043             :  * read from STDIN rather than a file.
   19044             :  */
   19045             : static void
   19046          52 : read_dump_filters(const char *filename, DumpOptions *dopt)
   19047             : {
   19048             :     FilterStateData fstate;
   19049             :     char       *objname;
   19050             :     FilterCommandType comtype;
   19051             :     FilterObjectType objtype;
   19052             : 
   19053          52 :     filter_init(&fstate, filename, exit_nicely);
   19054             : 
   19055         116 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   19056             :     {
   19057          66 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   19058             :         {
   19059          34 :             switch (objtype)
   19060             :             {
   19061           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19062           0 :                     break;
   19063           0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19064             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19065             :                 case FILTER_OBJECT_TYPE_INDEX:
   19066             :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19067             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19068             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19069           0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19070             :                                         "include",
   19071             :                                         filter_object_type_name(objtype));
   19072           0 :                     exit_nicely(1);
   19073             :                     break;      /* unreachable */
   19074             : 
   19075           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19076           2 :                     simple_string_list_append(&extension_include_patterns, objname);
   19077           2 :                     break;
   19078           2 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19079           2 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   19080           2 :                     break;
   19081           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19082           2 :                     simple_string_list_append(&schema_include_patterns, objname);
   19083           2 :                     dopt->include_everything = false;
   19084           2 :                     break;
   19085          26 :                 case FILTER_OBJECT_TYPE_TABLE:
   19086          26 :                     simple_string_list_append(&table_include_patterns, objname);
   19087          26 :                     dopt->include_everything = false;
   19088          26 :                     break;
   19089           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19090           2 :                     simple_string_list_append(&table_include_patterns_and_children,
   19091             :                                               objname);
   19092           2 :                     dopt->include_everything = false;
   19093           2 :                     break;
   19094             :             }
   19095          34 :         }
   19096          32 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   19097             :         {
   19098          18 :             switch (objtype)
   19099             :             {
   19100           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19101           0 :                     break;
   19102           2 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19103             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19104             :                 case FILTER_OBJECT_TYPE_INDEX:
   19105             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19106             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19107           2 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19108             :                                         "exclude",
   19109             :                                         filter_object_type_name(objtype));
   19110           2 :                     exit_nicely(1);
   19111             :                     break;
   19112             : 
   19113           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19114           2 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   19115           2 :                     break;
   19116           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19117           2 :                     simple_string_list_append(&tabledata_exclude_patterns,
   19118             :                                               objname);
   19119           2 :                     break;
   19120           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19121           2 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   19122             :                                               objname);
   19123           2 :                     break;
   19124           4 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19125           4 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   19126           4 :                     break;
   19127           4 :                 case FILTER_OBJECT_TYPE_TABLE:
   19128           4 :                     simple_string_list_append(&table_exclude_patterns, objname);
   19129           4 :                     break;
   19130           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19131           2 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   19132             :                                               objname);
   19133           2 :                     break;
   19134             :             }
   19135          16 :         }
   19136             :         else
   19137             :         {
   19138             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   19139             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   19140             :         }
   19141             : 
   19142          64 :         if (objname)
   19143          50 :             free(objname);
   19144             :     }
   19145             : 
   19146          44 :     filter_free(&fstate);
   19147          44 : }

Generated by: LCOV version 1.14