LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_dump.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 7066 7828 90.3 %
Date: 2025-02-22 07:14:56 Functions: 187 191 97.9 %
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-2025, 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_proc_d.h"
      53             : #include "catalog/pg_publication_d.h"
      54             : #include "catalog/pg_subscription_d.h"
      55             : #include "catalog/pg_type_d.h"
      56             : #include "common/connect.h"
      57             : #include "common/int.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 struct
      96             : {
      97             :     Oid         oid;            /* object OID */
      98             :     char        relkind;        /* object kind */
      99             :     RelFileNumber relfilenumber;    /* object filenode */
     100             :     Oid         toast_oid;      /* toast table OID */
     101             :     RelFileNumber toast_relfilenumber;  /* toast table filenode */
     102             :     Oid         toast_index_oid;    /* toast table index OID */
     103             :     RelFileNumber toast_index_relfilenumber;    /* toast table index filenode */
     104             : } BinaryUpgradeClassOidItem;
     105             : 
     106             : /* sequence types */
     107             : typedef enum SeqType
     108             : {
     109             :     SEQTYPE_SMALLINT,
     110             :     SEQTYPE_INTEGER,
     111             :     SEQTYPE_BIGINT,
     112             : } SeqType;
     113             : 
     114             : static const char *const SeqTypeNames[] =
     115             : {
     116             :     [SEQTYPE_SMALLINT] = "smallint",
     117             :     [SEQTYPE_INTEGER] = "integer",
     118             :     [SEQTYPE_BIGINT] = "bigint",
     119             : };
     120             : 
     121             : StaticAssertDecl(lengthof(SeqTypeNames) == (SEQTYPE_BIGINT + 1),
     122             :                  "array length mismatch");
     123             : 
     124             : typedef struct
     125             : {
     126             :     Oid         oid;            /* sequence OID */
     127             :     SeqType     seqtype;        /* data type of sequence */
     128             :     bool        cycled;         /* whether sequence cycles */
     129             :     int64       minv;           /* minimum value */
     130             :     int64       maxv;           /* maximum value */
     131             :     int64       startv;         /* start value */
     132             :     int64       incby;          /* increment value */
     133             :     int64       cache;          /* cache size */
     134             :     int64       last_value;     /* last value of sequence */
     135             :     bool        is_called;      /* whether nextval advances before returning */
     136             : } SequenceItem;
     137             : 
     138             : typedef enum OidOptions
     139             : {
     140             :     zeroIsError = 1,
     141             :     zeroAsStar = 2,
     142             :     zeroAsNone = 4,
     143             : } OidOptions;
     144             : 
     145             : /* global decls */
     146             : static bool dosync = true;      /* Issue fsync() to make dump durable on disk. */
     147             : 
     148             : static Oid  g_last_builtin_oid; /* value of the last builtin oid */
     149             : 
     150             : /* The specified names/patterns should to match at least one entity */
     151             : static int  strict_names = 0;
     152             : 
     153             : static pg_compress_algorithm compression_algorithm = PG_COMPRESSION_NONE;
     154             : 
     155             : /*
     156             :  * Object inclusion/exclusion lists
     157             :  *
     158             :  * The string lists record the patterns given by command-line switches,
     159             :  * which we then convert to lists of OIDs of matching objects.
     160             :  */
     161             : static SimpleStringList schema_include_patterns = {NULL, NULL};
     162             : static SimpleOidList schema_include_oids = {NULL, NULL};
     163             : static SimpleStringList schema_exclude_patterns = {NULL, NULL};
     164             : static SimpleOidList schema_exclude_oids = {NULL, NULL};
     165             : 
     166             : static SimpleStringList table_include_patterns = {NULL, NULL};
     167             : static SimpleStringList table_include_patterns_and_children = {NULL, NULL};
     168             : static SimpleOidList table_include_oids = {NULL, NULL};
     169             : static SimpleStringList table_exclude_patterns = {NULL, NULL};
     170             : static SimpleStringList table_exclude_patterns_and_children = {NULL, NULL};
     171             : static SimpleOidList table_exclude_oids = {NULL, NULL};
     172             : static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
     173             : static SimpleStringList tabledata_exclude_patterns_and_children = {NULL, NULL};
     174             : static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
     175             : 
     176             : static SimpleStringList foreign_servers_include_patterns = {NULL, NULL};
     177             : static SimpleOidList foreign_servers_include_oids = {NULL, NULL};
     178             : 
     179             : static SimpleStringList extension_include_patterns = {NULL, NULL};
     180             : static SimpleOidList extension_include_oids = {NULL, NULL};
     181             : 
     182             : static SimpleStringList extension_exclude_patterns = {NULL, NULL};
     183             : static SimpleOidList extension_exclude_oids = {NULL, NULL};
     184             : 
     185             : static const CatalogId nilCatalogId = {0, 0};
     186             : 
     187             : /* override for standard extra_float_digits setting */
     188             : static bool have_extra_float_digits = false;
     189             : static int  extra_float_digits;
     190             : 
     191             : /* sorted table of role names */
     192             : static RoleNameItem *rolenames = NULL;
     193             : static int  nrolenames = 0;
     194             : 
     195             : /* sorted table of comments */
     196             : static CommentItem *comments = NULL;
     197             : static int  ncomments = 0;
     198             : 
     199             : /* sorted table of security labels */
     200             : static SecLabelItem *seclabels = NULL;
     201             : static int  nseclabels = 0;
     202             : 
     203             : /* sorted table of pg_class information for binary upgrade */
     204             : static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
     205             : static int  nbinaryUpgradeClassOids = 0;
     206             : 
     207             : /* sorted table of sequences */
     208             : static SequenceItem *sequences = NULL;
     209             : static int  nsequences = 0;
     210             : 
     211             : /*
     212             :  * The default number of rows per INSERT when
     213             :  * --inserts is specified without --rows-per-insert
     214             :  */
     215             : #define DUMP_DEFAULT_ROWS_PER_INSERT 1
     216             : 
     217             : /*
     218             :  * Maximum number of large objects to group into a single ArchiveEntry.
     219             :  * At some point we might want to make this user-controllable, but for now
     220             :  * a hard-wired setting will suffice.
     221             :  */
     222             : #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
     223             : 
     224             : /*
     225             :  * Macro for producing quoted, schema-qualified name of a dumpable object.
     226             :  */
     227             : #define fmtQualifiedDumpable(obj) \
     228             :     fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
     229             :                    (obj)->dobj.name)
     230             : 
     231             : static void help(const char *progname);
     232             : static void setup_connection(Archive *AH,
     233             :                              const char *dumpencoding, const char *dumpsnapshot,
     234             :                              char *use_role);
     235             : static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
     236             : static void expand_schema_name_patterns(Archive *fout,
     237             :                                         SimpleStringList *patterns,
     238             :                                         SimpleOidList *oids,
     239             :                                         bool strict_names);
     240             : static void expand_extension_name_patterns(Archive *fout,
     241             :                                            SimpleStringList *patterns,
     242             :                                            SimpleOidList *oids,
     243             :                                            bool strict_names);
     244             : static void expand_foreign_server_name_patterns(Archive *fout,
     245             :                                                 SimpleStringList *patterns,
     246             :                                                 SimpleOidList *oids);
     247             : static void expand_table_name_patterns(Archive *fout,
     248             :                                        SimpleStringList *patterns,
     249             :                                        SimpleOidList *oids,
     250             :                                        bool strict_names,
     251             :                                        bool with_child_tables);
     252             : static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
     253             :                                   const char *pattern);
     254             : 
     255             : static NamespaceInfo *findNamespace(Oid nsoid);
     256             : static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
     257             : static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
     258             : static const char *getRoleName(const char *roleoid_str);
     259             : static void collectRoleNames(Archive *fout);
     260             : static void getAdditionalACLs(Archive *fout);
     261             : static void dumpCommentExtended(Archive *fout, const char *type,
     262             :                                 const char *name, const char *namespace,
     263             :                                 const char *owner, CatalogId catalogId,
     264             :                                 int subid, DumpId dumpId,
     265             :                                 const char *initdb_comment);
     266             : static inline void dumpComment(Archive *fout, const char *type,
     267             :                                const char *name, const char *namespace,
     268             :                                const char *owner, CatalogId catalogId,
     269             :                                int subid, DumpId dumpId);
     270             : static int  findComments(Oid classoid, Oid objoid, CommentItem **items);
     271             : static void collectComments(Archive *fout);
     272             : static void dumpSecLabel(Archive *fout, const char *type, const char *name,
     273             :                          const char *namespace, const char *owner,
     274             :                          CatalogId catalogId, int subid, DumpId dumpId);
     275             : static int  findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
     276             : static void collectSecLabels(Archive *fout);
     277             : static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
     278             : static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
     279             : static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
     280             : static void dumpType(Archive *fout, const TypeInfo *tyinfo);
     281             : static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
     282             : static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
     283             : static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
     284             : static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
     285             : static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
     286             : static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
     287             : static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
     288             :                                          PGresult *res);
     289             : static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
     290             : static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
     291             : static void dumpFunc(Archive *fout, const FuncInfo *finfo);
     292             : static void dumpCast(Archive *fout, const CastInfo *cast);
     293             : static void dumpTransform(Archive *fout, const TransformInfo *transform);
     294             : static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
     295             : static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
     296             : static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
     297             : static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
     298             : static void dumpCollation(Archive *fout, const CollInfo *collinfo);
     299             : static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
     300             : static void dumpRule(Archive *fout, const RuleInfo *rinfo);
     301             : static void dumpAgg(Archive *fout, const AggInfo *agginfo);
     302             : static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
     303             : static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
     304             : static void dumpTable(Archive *fout, const TableInfo *tbinfo);
     305             : static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
     306             : static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
     307             : static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
     308             : static void collectSequences(Archive *fout);
     309             : static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
     310             : static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
     311             : static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
     312             : static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
     313             : static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
     314             : static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
     315             : static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
     316             : static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
     317             : static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
     318             : static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
     319             : static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
     320             : static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
     321             : static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
     322             : static void dumpUserMappings(Archive *fout,
     323             :                              const char *servername, const char *namespace,
     324             :                              const char *owner, CatalogId catalogId, DumpId dumpId);
     325             : static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
     326             : 
     327             : static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
     328             :                       const char *type, const char *name, const char *subname,
     329             :                       const char *nspname, const char *tag, const char *owner,
     330             :                       const DumpableAcl *dacl);
     331             : 
     332             : static void getDependencies(Archive *fout);
     333             : static void BuildArchiveDependencies(Archive *fout);
     334             : static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
     335             :                                      DumpId **dependencies, int *nDeps, int *allocDeps);
     336             : 
     337             : static DumpableObject *createBoundaryObjects(void);
     338             : static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
     339             :                                     DumpableObject *boundaryObjs);
     340             : 
     341             : static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
     342             : static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
     343             : static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
     344             : static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
     345             : static void buildMatViewRefreshDependencies(Archive *fout);
     346             : static void getTableDataFKConstraints(void);
     347             : static void determineNotNullFlags(Archive *fout, PGresult *res, int r,
     348             :                                   TableInfo *tbinfo, int j,
     349             :                                   int i_notnull_name, int i_notnull_noinherit,
     350             :                                   int i_notnull_islocal);
     351             : static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
     352             :                                        bool is_agg);
     353             : static char *format_function_signature(Archive *fout,
     354             :                                        const FuncInfo *finfo, bool honor_quotes);
     355             : static char *convertRegProcReference(const char *proc);
     356             : static char *getFormattedOperatorName(const char *oproid);
     357             : static char *convertTSFunction(Archive *fout, Oid funcOid);
     358             : static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
     359             : static void getLOs(Archive *fout);
     360             : static void dumpLO(Archive *fout, const LoInfo *loinfo);
     361             : static int  dumpLOs(Archive *fout, const void *arg);
     362             : static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
     363             : static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
     364             : static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
     365             : static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
     366             : static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
     367             : static void dumpDatabase(Archive *fout);
     368             : static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
     369             :                                const char *dbname, Oid dboid);
     370             : static void dumpEncoding(Archive *AH);
     371             : static void dumpStdStrings(Archive *AH);
     372             : static void dumpSearchPath(Archive *AH);
     373             : static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
     374             :                                                      PQExpBuffer upgrade_buffer,
     375             :                                                      Oid pg_type_oid,
     376             :                                                      bool force_array_type,
     377             :                                                      bool include_multirange_type);
     378             : static void binary_upgrade_set_type_oids_by_rel(Archive *fout,
     379             :                                                 PQExpBuffer upgrade_buffer,
     380             :                                                 const TableInfo *tbinfo);
     381             : static void collectBinaryUpgradeClassOids(Archive *fout);
     382             : static void binary_upgrade_set_pg_class_oids(Archive *fout,
     383             :                                              PQExpBuffer upgrade_buffer,
     384             :                                              Oid pg_class_oid);
     385             : static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
     386             :                                             const DumpableObject *dobj,
     387             :                                             const char *objtype,
     388             :                                             const char *objname,
     389             :                                             const char *objnamespace);
     390             : static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
     391             : static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
     392             : static bool nonemptyReloptions(const char *reloptions);
     393             : static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
     394             :                                     const char *prefix, Archive *fout);
     395             : static char *get_synchronized_snapshot(Archive *fout);
     396             : static void set_restrict_relation_kind(Archive *AH, const char *value);
     397             : static void setupDumpWorker(Archive *AH);
     398             : static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
     399             : static bool forcePartitionRootLoad(const TableInfo *tbinfo);
     400             : static void read_dump_filters(const char *filename, DumpOptions *dopt);
     401             : 
     402             : 
     403             : int
     404         508 : main(int argc, char **argv)
     405             : {
     406             :     int         c;
     407         508 :     const char *filename = NULL;
     408         508 :     const char *format = "p";
     409             :     TableInfo  *tblinfo;
     410             :     int         numTables;
     411             :     DumpableObject **dobjs;
     412             :     int         numObjs;
     413             :     DumpableObject *boundaryObjs;
     414             :     int         i;
     415             :     int         optindex;
     416             :     RestoreOptions *ropt;
     417             :     Archive    *fout;           /* the script file */
     418         508 :     bool        g_verbose = false;
     419         508 :     const char *dumpencoding = NULL;
     420         508 :     const char *dumpsnapshot = NULL;
     421         508 :     char       *use_role = NULL;
     422         508 :     int         numWorkers = 1;
     423         508 :     int         plainText = 0;
     424         508 :     ArchiveFormat archiveFormat = archUnknown;
     425             :     ArchiveMode archiveMode;
     426         508 :     pg_compress_specification compression_spec = {0};
     427         508 :     char       *compression_detail = NULL;
     428         508 :     char       *compression_algorithm_str = "none";
     429         508 :     char       *error_detail = NULL;
     430         508 :     bool        user_compression_defined = false;
     431         508 :     DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
     432         508 :     bool        data_only = false;
     433         508 :     bool        schema_only = false;
     434         508 :     bool        statistics_only = false;
     435         508 :     bool        no_data = false;
     436         508 :     bool        no_schema = false;
     437         508 :     bool        no_statistics = false;
     438             : 
     439             :     static DumpOptions dopt;
     440             : 
     441             :     static struct option long_options[] = {
     442             :         {"data-only", no_argument, NULL, 'a'},
     443             :         {"blobs", no_argument, NULL, 'b'},
     444             :         {"large-objects", no_argument, NULL, 'b'},
     445             :         {"no-blobs", no_argument, NULL, 'B'},
     446             :         {"no-large-objects", no_argument, NULL, 'B'},
     447             :         {"clean", no_argument, NULL, 'c'},
     448             :         {"create", no_argument, NULL, 'C'},
     449             :         {"dbname", required_argument, NULL, 'd'},
     450             :         {"extension", required_argument, NULL, 'e'},
     451             :         {"file", required_argument, NULL, 'f'},
     452             :         {"format", required_argument, NULL, 'F'},
     453             :         {"host", required_argument, NULL, 'h'},
     454             :         {"jobs", 1, NULL, 'j'},
     455             :         {"no-reconnect", no_argument, NULL, 'R'},
     456             :         {"no-owner", no_argument, NULL, 'O'},
     457             :         {"port", required_argument, NULL, 'p'},
     458             :         {"schema", required_argument, NULL, 'n'},
     459             :         {"exclude-schema", required_argument, NULL, 'N'},
     460             :         {"schema-only", no_argument, NULL, 's'},
     461             :         {"superuser", required_argument, NULL, 'S'},
     462             :         {"table", required_argument, NULL, 't'},
     463             :         {"exclude-table", required_argument, NULL, 'T'},
     464             :         {"no-password", no_argument, NULL, 'w'},
     465             :         {"password", no_argument, NULL, 'W'},
     466             :         {"username", required_argument, NULL, 'U'},
     467             :         {"verbose", no_argument, NULL, 'v'},
     468             :         {"no-privileges", no_argument, NULL, 'x'},
     469             :         {"no-acl", no_argument, NULL, 'x'},
     470             :         {"compress", required_argument, NULL, 'Z'},
     471             :         {"encoding", required_argument, NULL, 'E'},
     472             :         {"help", no_argument, NULL, '?'},
     473             :         {"version", no_argument, NULL, 'V'},
     474             : 
     475             :         /*
     476             :          * the following options don't have an equivalent short option letter
     477             :          */
     478             :         {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
     479             :         {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
     480             :         {"column-inserts", no_argument, &dopt.column_inserts, 1},
     481             :         {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
     482             :         {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
     483             :         {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
     484             :         {"exclude-table-data", required_argument, NULL, 4},
     485             :         {"extra-float-digits", required_argument, NULL, 8},
     486             :         {"if-exists", no_argument, &dopt.if_exists, 1},
     487             :         {"inserts", no_argument, NULL, 9},
     488             :         {"lock-wait-timeout", required_argument, NULL, 2},
     489             :         {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
     490             :         {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
     491             :         {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
     492             :         {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
     493             :         {"role", required_argument, NULL, 3},
     494             :         {"section", required_argument, NULL, 5},
     495             :         {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
     496             :         {"snapshot", required_argument, NULL, 6},
     497             :         {"statistics-only", no_argument, NULL, 18},
     498             :         {"strict-names", no_argument, &strict_names, 1},
     499             :         {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
     500             :         {"no-comments", no_argument, &dopt.no_comments, 1},
     501             :         {"no-data", no_argument, NULL, 19},
     502             :         {"no-publications", no_argument, &dopt.no_publications, 1},
     503             :         {"no-schema", no_argument, NULL, 20},
     504             :         {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
     505             :         {"no-statistics", no_argument, NULL, 21},
     506             :         {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
     507             :         {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
     508             :         {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
     509             :         {"no-sync", no_argument, NULL, 7},
     510             :         {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
     511             :         {"rows-per-insert", required_argument, NULL, 10},
     512             :         {"include-foreign-data", required_argument, NULL, 11},
     513             :         {"table-and-children", required_argument, NULL, 12},
     514             :         {"exclude-table-and-children", required_argument, NULL, 13},
     515             :         {"exclude-table-data-and-children", required_argument, NULL, 14},
     516             :         {"sync-method", required_argument, NULL, 15},
     517             :         {"filter", required_argument, NULL, 16},
     518             :         {"exclude-extension", required_argument, NULL, 17},
     519             : 
     520             :         {NULL, 0, NULL, 0}
     521             :     };
     522             : 
     523         508 :     pg_logging_init(argv[0]);
     524         508 :     pg_logging_set_level(PG_LOG_WARNING);
     525         508 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
     526             : 
     527             :     /*
     528             :      * Initialize what we need for parallel execution, especially for thread
     529             :      * support on Windows.
     530             :      */
     531         508 :     init_parallel_dump_utils();
     532             : 
     533         508 :     progname = get_progname(argv[0]);
     534             : 
     535         508 :     if (argc > 1)
     536             :     {
     537         508 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     538             :         {
     539           2 :             help(progname);
     540           2 :             exit_nicely(0);
     541             :         }
     542         506 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     543             :         {
     544          98 :             puts("pg_dump (PostgreSQL) " PG_VERSION);
     545          98 :             exit_nicely(0);
     546             :         }
     547             :     }
     548             : 
     549         408 :     InitDumpOptions(&dopt);
     550             : 
     551        1816 :     while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:",
     552             :                             long_options, &optindex)) != -1)
     553             :     {
     554        1424 :         switch (c)
     555             :         {
     556          18 :             case 'a':           /* Dump data only */
     557          18 :                 data_only = true;
     558          18 :                 break;
     559             : 
     560           2 :             case 'b':           /* Dump LOs */
     561           2 :                 dopt.outputLOs = true;
     562           2 :                 break;
     563             : 
     564           4 :             case 'B':           /* Don't dump LOs */
     565           4 :                 dopt.dontOutputLOs = true;
     566           4 :                 break;
     567             : 
     568          12 :             case 'c':           /* clean (i.e., drop) schema prior to create */
     569          12 :                 dopt.outputClean = 1;
     570          12 :                 break;
     571             : 
     572          58 :             case 'C':           /* Create DB */
     573          58 :                 dopt.outputCreateDB = 1;
     574          58 :                 break;
     575             : 
     576          10 :             case 'd':           /* database name */
     577          10 :                 dopt.cparams.dbname = pg_strdup(optarg);
     578          10 :                 break;
     579             : 
     580           8 :             case 'e':           /* include extension(s) */
     581           8 :                 simple_string_list_append(&extension_include_patterns, optarg);
     582           8 :                 dopt.include_everything = false;
     583           8 :                 break;
     584             : 
     585           4 :             case 'E':           /* Dump encoding */
     586           4 :                 dumpencoding = pg_strdup(optarg);
     587           4 :                 break;
     588             : 
     589         318 :             case 'f':
     590         318 :                 filename = pg_strdup(optarg);
     591         318 :                 break;
     592             : 
     593         174 :             case 'F':
     594         174 :                 format = pg_strdup(optarg);
     595         174 :                 break;
     596             : 
     597          28 :             case 'h':           /* server host */
     598          28 :                 dopt.cparams.pghost = pg_strdup(optarg);
     599          28 :                 break;
     600             : 
     601          22 :             case 'j':           /* number of dump jobs */
     602          22 :                 if (!option_parse_int(optarg, "-j/--jobs", 1,
     603             :                                       PG_MAX_JOBS,
     604             :                                       &numWorkers))
     605           2 :                     exit_nicely(1);
     606          20 :                 break;
     607             : 
     608          34 :             case 'n':           /* include schema(s) */
     609          34 :                 simple_string_list_append(&schema_include_patterns, optarg);
     610          34 :                 dopt.include_everything = false;
     611          34 :                 break;
     612             : 
     613           2 :             case 'N':           /* exclude schema(s) */
     614           2 :                 simple_string_list_append(&schema_exclude_patterns, optarg);
     615           2 :                 break;
     616             : 
     617           4 :             case 'O':           /* Don't reconnect to match owner */
     618           4 :                 dopt.outputNoOwner = 1;
     619           4 :                 break;
     620             : 
     621         104 :             case 'p':           /* server port */
     622         104 :                 dopt.cparams.pgport = pg_strdup(optarg);
     623         104 :                 break;
     624             : 
     625           4 :             case 'R':
     626             :                 /* no-op, still accepted for backwards compatibility */
     627           4 :                 break;
     628             : 
     629          12 :             case 's':           /* dump schema only */
     630          12 :                 schema_only = true;
     631          12 :                 break;
     632             : 
     633           2 :             case 'S':           /* Username for superuser in plain text output */
     634           2 :                 dopt.outputSuperuser = pg_strdup(optarg);
     635           2 :                 break;
     636             : 
     637          16 :             case 't':           /* include table(s) */
     638          16 :                 simple_string_list_append(&table_include_patterns, optarg);
     639          16 :                 dopt.include_everything = false;
     640          16 :                 break;
     641             : 
     642           8 :             case 'T':           /* exclude table(s) */
     643           8 :                 simple_string_list_append(&table_exclude_patterns, optarg);
     644           8 :                 break;
     645             : 
     646          32 :             case 'U':
     647          32 :                 dopt.cparams.username = pg_strdup(optarg);
     648          32 :                 break;
     649             : 
     650          12 :             case 'v':           /* verbose */
     651          12 :                 g_verbose = true;
     652          12 :                 pg_logging_increase_verbosity();
     653          12 :                 break;
     654             : 
     655           2 :             case 'w':
     656           2 :                 dopt.cparams.promptPassword = TRI_NO;
     657           2 :                 break;
     658             : 
     659           0 :             case 'W':
     660           0 :                 dopt.cparams.promptPassword = TRI_YES;
     661           0 :                 break;
     662             : 
     663           4 :             case 'x':           /* skip ACL dump */
     664           4 :                 dopt.aclsSkip = true;
     665           4 :                 break;
     666             : 
     667          24 :             case 'Z':           /* Compression */
     668          24 :                 parse_compress_options(optarg, &compression_algorithm_str,
     669             :                                        &compression_detail);
     670          24 :                 user_compression_defined = true;
     671          24 :                 break;
     672             : 
     673         108 :             case 0:
     674             :                 /* This covers the long options. */
     675         108 :                 break;
     676             : 
     677           4 :             case 2:             /* lock-wait-timeout */
     678           4 :                 dopt.lockWaitTimeout = pg_strdup(optarg);
     679           4 :                 break;
     680             : 
     681           6 :             case 3:             /* SET ROLE */
     682           6 :                 use_role = pg_strdup(optarg);
     683           6 :                 break;
     684             : 
     685           2 :             case 4:             /* exclude table(s) data */
     686           2 :                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
     687           2 :                 break;
     688             : 
     689          12 :             case 5:             /* section */
     690          12 :                 set_dump_section(optarg, &dopt.dumpSections);
     691          12 :                 break;
     692             : 
     693           0 :             case 6:             /* snapshot */
     694           0 :                 dumpsnapshot = pg_strdup(optarg);
     695           0 :                 break;
     696             : 
     697         234 :             case 7:             /* no-sync */
     698         234 :                 dosync = false;
     699         234 :                 break;
     700             : 
     701           2 :             case 8:
     702           2 :                 have_extra_float_digits = true;
     703           2 :                 if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
     704             :                                       &extra_float_digits))
     705           2 :                     exit_nicely(1);
     706           0 :                 break;
     707             : 
     708           4 :             case 9:             /* inserts */
     709             : 
     710             :                 /*
     711             :                  * dump_inserts also stores --rows-per-insert, careful not to
     712             :                  * overwrite that.
     713             :                  */
     714           4 :                 if (dopt.dump_inserts == 0)
     715           4 :                     dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     716           4 :                 break;
     717             : 
     718           4 :             case 10:            /* rows per insert */
     719           4 :                 if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
     720             :                                       &dopt.dump_inserts))
     721           2 :                     exit_nicely(1);
     722           2 :                 break;
     723             : 
     724           8 :             case 11:            /* include foreign data */
     725           8 :                 simple_string_list_append(&foreign_servers_include_patterns,
     726             :                                           optarg);
     727           8 :                 break;
     728             : 
     729           2 :             case 12:            /* include table(s) and their children */
     730           2 :                 simple_string_list_append(&table_include_patterns_and_children,
     731             :                                           optarg);
     732           2 :                 dopt.include_everything = false;
     733           2 :                 break;
     734             : 
     735           2 :             case 13:            /* exclude table(s) and their children */
     736           2 :                 simple_string_list_append(&table_exclude_patterns_and_children,
     737             :                                           optarg);
     738           2 :                 break;
     739             : 
     740           2 :             case 14:            /* exclude data of table(s) and children */
     741           2 :                 simple_string_list_append(&tabledata_exclude_patterns_and_children,
     742             :                                           optarg);
     743           2 :                 break;
     744             : 
     745           0 :             case 15:
     746           0 :                 if (!parse_sync_method(optarg, &sync_method))
     747           0 :                     exit_nicely(1);
     748           0 :                 break;
     749             : 
     750          52 :             case 16:            /* read object filters from file */
     751          52 :                 read_dump_filters(optarg, &dopt);
     752          44 :                 break;
     753             : 
     754           2 :             case 17:            /* exclude extension(s) */
     755           2 :                 simple_string_list_append(&extension_exclude_patterns,
     756             :                                           optarg);
     757           2 :                 break;
     758             : 
     759           8 :             case 18:
     760           8 :                 statistics_only = true;
     761           8 :                 break;
     762             : 
     763          32 :             case 19:
     764          32 :                 no_data = true;
     765          32 :                 break;
     766             : 
     767           4 :             case 20:
     768           4 :                 no_schema = true;
     769           4 :                 break;
     770             : 
     771          16 :             case 21:
     772          16 :                 no_statistics = true;
     773          16 :                 break;
     774             : 
     775           2 :             default:
     776             :                 /* getopt_long already emitted a complaint */
     777           2 :                 pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     778           2 :                 exit_nicely(1);
     779             :         }
     780             :     }
     781             : 
     782             :     /*
     783             :      * Non-option argument specifies database name as long as it wasn't
     784             :      * already specified with -d / --dbname
     785             :      */
     786         392 :     if (optind < argc && dopt.cparams.dbname == NULL)
     787         322 :         dopt.cparams.dbname = argv[optind++];
     788             : 
     789             :     /* Complain if any arguments remain */
     790         392 :     if (optind < argc)
     791             :     {
     792           2 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     793             :                      argv[optind]);
     794           2 :         pg_log_error_hint("Try \"%s --help\" for more information.", progname);
     795           2 :         exit_nicely(1);
     796             :     }
     797             : 
     798             :     /* --column-inserts implies --inserts */
     799         390 :     if (dopt.column_inserts && dopt.dump_inserts == 0)
     800           2 :         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
     801             : 
     802             :     /*
     803             :      * Binary upgrade mode implies dumping sequence data even in schema-only
     804             :      * mode.  This is not exposed as a separate option, but kept separate
     805             :      * internally for clarity.
     806             :      */
     807         390 :     if (dopt.binary_upgrade)
     808          32 :         dopt.sequence_data = 1;
     809             : 
     810         390 :     if (data_only && schema_only)
     811           2 :         pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
     812         388 :     if (schema_only && statistics_only)
     813           2 :         pg_fatal("options -s/--schema-only and --statistics-only cannot be used together");
     814         386 :     if (data_only && statistics_only)
     815           2 :         pg_fatal("options -a/--data-only and --statistics-only cannot be used together");
     816             : 
     817         384 :     if (data_only && no_data)
     818           0 :         pg_fatal("options -a/--data-only and --no-data cannot be used together");
     819         384 :     if (schema_only && no_schema)
     820           0 :         pg_fatal("options -s/--schema-only and --no-schema cannot be used together");
     821         384 :     if (statistics_only && no_statistics)
     822           2 :         pg_fatal("options --statistics-only and --no-statistics cannot be used together");
     823             : 
     824         382 :     if (schema_only && foreign_servers_include_patterns.head != NULL)
     825           2 :         pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
     826             : 
     827         380 :     if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
     828           2 :         pg_fatal("option --include-foreign-data is not supported with parallel backup");
     829             : 
     830         378 :     if (data_only && dopt.outputClean)
     831           2 :         pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
     832             : 
     833         376 :     if (dopt.if_exists && !dopt.outputClean)
     834           2 :         pg_fatal("option --if-exists requires option -c/--clean");
     835             : 
     836             :     /* set derivative flags */
     837         374 :     dopt.dumpData = data_only || (!schema_only && !statistics_only && !no_data);
     838         374 :     dopt.dumpSchema = schema_only || (!data_only && !statistics_only && !no_schema);
     839         374 :     dopt.dumpStatistics = statistics_only || (!data_only && !schema_only && !no_statistics);
     840             : 
     841             :     /*
     842             :      * --inserts are already implied above if --column-inserts or
     843             :      * --rows-per-insert were specified.
     844             :      */
     845         374 :     if (dopt.do_nothing && dopt.dump_inserts == 0)
     846           2 :         pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
     847             : 
     848             :     /* Identify archive format to emit */
     849         372 :     archiveFormat = parseArchiveFormat(format, &archiveMode);
     850             : 
     851             :     /* archiveFormat specific setup */
     852         370 :     if (archiveFormat == archNull)
     853         302 :         plainText = 1;
     854             : 
     855             :     /*
     856             :      * Custom and directory formats are compressed by default with gzip when
     857             :      * available, not the others.  If gzip is not available, no compression is
     858             :      * done by default.
     859             :      */
     860         370 :     if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
     861          62 :         !user_compression_defined)
     862             :     {
     863             : #ifdef HAVE_LIBZ
     864          52 :         compression_algorithm_str = "gzip";
     865             : #else
     866             :         compression_algorithm_str = "none";
     867             : #endif
     868             :     }
     869             : 
     870             :     /*
     871             :      * Compression options
     872             :      */
     873         370 :     if (!parse_compress_algorithm(compression_algorithm_str,
     874             :                                   &compression_algorithm))
     875           2 :         pg_fatal("unrecognized compression algorithm: \"%s\"",
     876             :                  compression_algorithm_str);
     877             : 
     878         368 :     parse_compress_specification(compression_algorithm, compression_detail,
     879             :                                  &compression_spec);
     880         368 :     error_detail = validate_compress_specification(&compression_spec);
     881         368 :     if (error_detail != NULL)
     882           6 :         pg_fatal("invalid compression specification: %s",
     883             :                  error_detail);
     884             : 
     885         362 :     error_detail = supports_compression(compression_spec);
     886         362 :     if (error_detail != NULL)
     887           0 :         pg_fatal("%s", error_detail);
     888             : 
     889             :     /*
     890             :      * Disable support for zstd workers for now - these are based on
     891             :      * threading, and it's unclear how it interacts with parallel dumps on
     892             :      * platforms where that relies on threads too (e.g. Windows).
     893             :      */
     894         362 :     if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
     895           0 :         pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
     896             :                        "workers");
     897             : 
     898             :     /*
     899             :      * If emitting an archive format, we always want to emit a DATABASE item,
     900             :      * in case --create is specified at pg_restore time.
     901             :      */
     902         362 :     if (!plainText)
     903          68 :         dopt.outputCreateDB = 1;
     904             : 
     905             :     /* Parallel backup only in the directory archive format so far */
     906         362 :     if (archiveFormat != archDirectory && numWorkers > 1)
     907           2 :         pg_fatal("parallel backup only supported by the directory format");
     908             : 
     909             :     /* Open the output file */
     910         360 :     fout = CreateArchive(filename, archiveFormat, compression_spec,
     911             :                          dosync, archiveMode, setupDumpWorker, sync_method);
     912             : 
     913             :     /* Make dump options accessible right away */
     914         358 :     SetArchiveOptions(fout, &dopt, NULL);
     915             : 
     916             :     /* Register the cleanup hook */
     917         358 :     on_exit_close_archive(fout);
     918             : 
     919             :     /* Let the archiver know how noisy to be */
     920         358 :     fout->verbose = g_verbose;
     921             : 
     922             : 
     923             :     /*
     924             :      * We allow the server to be back to 9.2, and up to any minor release of
     925             :      * our own major version.  (See also version check in pg_dumpall.c.)
     926             :      */
     927         358 :     fout->minRemoteVersion = 90200;
     928         358 :     fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
     929             : 
     930         358 :     fout->numWorkers = numWorkers;
     931             : 
     932             :     /*
     933             :      * Open the database using the Archiver, so it knows about it. Errors mean
     934             :      * death.
     935             :      */
     936         358 :     ConnectDatabase(fout, &dopt.cparams, false);
     937         354 :     setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
     938             : 
     939             :     /*
     940             :      * On hot standbys, never try to dump unlogged table data, since it will
     941             :      * just throw an error.
     942             :      */
     943         354 :     if (fout->isStandby)
     944           8 :         dopt.no_unlogged_table_data = true;
     945             : 
     946             :     /*
     947             :      * Find the last built-in OID, if needed (prior to 8.1)
     948             :      *
     949             :      * With 8.1 and above, we can just use FirstNormalObjectId - 1.
     950             :      */
     951         354 :     g_last_builtin_oid = FirstNormalObjectId - 1;
     952             : 
     953         354 :     pg_log_info("last built-in OID is %u", g_last_builtin_oid);
     954             : 
     955             :     /* Expand schema selection patterns into OID lists */
     956         354 :     if (schema_include_patterns.head != NULL)
     957             :     {
     958          36 :         expand_schema_name_patterns(fout, &schema_include_patterns,
     959             :                                     &schema_include_oids,
     960             :                                     strict_names);
     961          24 :         if (schema_include_oids.head == NULL)
     962           2 :             pg_fatal("no matching schemas were found");
     963             :     }
     964         340 :     expand_schema_name_patterns(fout, &schema_exclude_patterns,
     965             :                                 &schema_exclude_oids,
     966             :                                 false);
     967             :     /* non-matching exclusion patterns aren't an error */
     968             : 
     969             :     /* Expand table selection patterns into OID lists */
     970         340 :     expand_table_name_patterns(fout, &table_include_patterns,
     971             :                                &table_include_oids,
     972             :                                strict_names, false);
     973         330 :     expand_table_name_patterns(fout, &table_include_patterns_and_children,
     974             :                                &table_include_oids,
     975             :                                strict_names, true);
     976         330 :     if ((table_include_patterns.head != NULL ||
     977         308 :          table_include_patterns_and_children.head != NULL) &&
     978          26 :         table_include_oids.head == NULL)
     979           4 :         pg_fatal("no matching tables were found");
     980             : 
     981         326 :     expand_table_name_patterns(fout, &table_exclude_patterns,
     982             :                                &table_exclude_oids,
     983             :                                false, false);
     984         326 :     expand_table_name_patterns(fout, &table_exclude_patterns_and_children,
     985             :                                &table_exclude_oids,
     986             :                                false, true);
     987             : 
     988         326 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns,
     989             :                                &tabledata_exclude_oids,
     990             :                                false, false);
     991         326 :     expand_table_name_patterns(fout, &tabledata_exclude_patterns_and_children,
     992             :                                &tabledata_exclude_oids,
     993             :                                false, true);
     994             : 
     995         326 :     expand_foreign_server_name_patterns(fout, &foreign_servers_include_patterns,
     996             :                                         &foreign_servers_include_oids);
     997             : 
     998             :     /* non-matching exclusion patterns aren't an error */
     999             : 
    1000             :     /* Expand extension selection patterns into OID lists */
    1001         324 :     if (extension_include_patterns.head != NULL)
    1002             :     {
    1003          10 :         expand_extension_name_patterns(fout, &extension_include_patterns,
    1004             :                                        &extension_include_oids,
    1005             :                                        strict_names);
    1006          10 :         if (extension_include_oids.head == NULL)
    1007           2 :             pg_fatal("no matching extensions were found");
    1008             :     }
    1009         322 :     expand_extension_name_patterns(fout, &extension_exclude_patterns,
    1010             :                                    &extension_exclude_oids,
    1011             :                                    false);
    1012             :     /* non-matching exclusion patterns aren't an error */
    1013             : 
    1014             :     /*
    1015             :      * Dumping LOs is the default for dumps where an inclusion switch is not
    1016             :      * used (an "include everything" dump).  -B can be used to exclude LOs
    1017             :      * from those dumps.  -b can be used to include LOs even when an inclusion
    1018             :      * switch is used.
    1019             :      *
    1020             :      * -s means "schema only" and LOs are data, not schema, so we never
    1021             :      * include LOs when -s is used.
    1022             :      */
    1023         322 :     if (dopt.include_everything && dopt.dumpData && !dopt.dontOutputLOs)
    1024         232 :         dopt.outputLOs = true;
    1025             : 
    1026             :     /*
    1027             :      * Collect role names so we can map object owner OIDs to names.
    1028             :      */
    1029         322 :     collectRoleNames(fout);
    1030             : 
    1031             :     /*
    1032             :      * Now scan the database and create DumpableObject structs for all the
    1033             :      * objects we intend to dump.
    1034             :      */
    1035         322 :     tblinfo = getSchemaData(fout, &numTables);
    1036             : 
    1037         320 :     if (dopt.dumpData)
    1038             :     {
    1039         280 :         getTableData(&dopt, tblinfo, numTables, 0);
    1040         280 :         buildMatViewRefreshDependencies(fout);
    1041         280 :         if (!dopt.dumpSchema)
    1042          14 :             getTableDataFKConstraints();
    1043             :     }
    1044             : 
    1045         320 :     if (!dopt.dumpData && dopt.sequence_data)
    1046          32 :         getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
    1047             : 
    1048             :     /*
    1049             :      * In binary-upgrade mode, we do not have to worry about the actual LO
    1050             :      * data or the associated metadata that resides in the pg_largeobject and
    1051             :      * pg_largeobject_metadata tables, respectively.
    1052             :      *
    1053             :      * However, we do need to collect LO information as there may be comments
    1054             :      * or other information on LOs that we do need to dump out.
    1055             :      */
    1056         320 :     if (dopt.outputLOs || dopt.binary_upgrade)
    1057         264 :         getLOs(fout);
    1058             : 
    1059             :     /*
    1060             :      * Collect dependency data to assist in ordering the objects.
    1061             :      */
    1062         320 :     getDependencies(fout);
    1063             : 
    1064             :     /*
    1065             :      * Collect ACLs, comments, and security labels, if wanted.
    1066             :      */
    1067         320 :     if (!dopt.aclsSkip)
    1068         316 :         getAdditionalACLs(fout);
    1069         320 :     if (!dopt.no_comments)
    1070         320 :         collectComments(fout);
    1071         320 :     if (!dopt.no_security_labels)
    1072         320 :         collectSecLabels(fout);
    1073             : 
    1074             :     /* For binary upgrade mode, collect required pg_class information. */
    1075         320 :     if (dopt.binary_upgrade)
    1076          32 :         collectBinaryUpgradeClassOids(fout);
    1077             : 
    1078             :     /* Collect sequence information. */
    1079         320 :     collectSequences(fout);
    1080             : 
    1081             :     /* Lastly, create dummy objects to represent the section boundaries */
    1082         320 :     boundaryObjs = createBoundaryObjects();
    1083             : 
    1084             :     /* Get pointers to all the known DumpableObjects */
    1085         320 :     getDumpableObjects(&dobjs, &numObjs);
    1086             : 
    1087             :     /*
    1088             :      * Add dummy dependencies to enforce the dump section ordering.
    1089             :      */
    1090         320 :     addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
    1091             : 
    1092             :     /*
    1093             :      * Sort the objects into a safe dump order (no forward references).
    1094             :      *
    1095             :      * We rely on dependency information to help us determine a safe order, so
    1096             :      * the initial sort is mostly for cosmetic purposes: we sort by name to
    1097             :      * ensure that logically identical schemas will dump identically.
    1098             :      */
    1099         320 :     sortDumpableObjectsByTypeName(dobjs, numObjs);
    1100             : 
    1101         320 :     sortDumpableObjects(dobjs, numObjs,
    1102         320 :                         boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
    1103             : 
    1104             :     /*
    1105             :      * Create archive TOC entries for all the objects to be dumped, in a safe
    1106             :      * order.
    1107             :      */
    1108             : 
    1109             :     /*
    1110             :      * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
    1111             :      */
    1112         320 :     dumpEncoding(fout);
    1113         320 :     dumpStdStrings(fout);
    1114         320 :     dumpSearchPath(fout);
    1115             : 
    1116             :     /* The database items are always next, unless we don't want them at all */
    1117         320 :     if (dopt.outputCreateDB)
    1118         124 :         dumpDatabase(fout);
    1119             : 
    1120             :     /* Now the rearrangeable objects. */
    1121     1187560 :     for (i = 0; i < numObjs; i++)
    1122     1187240 :         dumpDumpableObject(fout, dobjs[i]);
    1123             : 
    1124             :     /*
    1125             :      * Set up options info to ensure we dump what we want.
    1126             :      */
    1127         320 :     ropt = NewRestoreOptions();
    1128         320 :     ropt->filename = filename;
    1129             : 
    1130             :     /* if you change this list, see dumpOptionsFromRestoreOptions */
    1131         320 :     ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
    1132         320 :     ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
    1133         320 :     ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
    1134         320 :     ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
    1135         320 :     ropt->cparams.promptPassword = dopt.cparams.promptPassword;
    1136         320 :     ropt->dropSchema = dopt.outputClean;
    1137         320 :     ropt->dumpData = dopt.dumpData;
    1138         320 :     ropt->dumpSchema = dopt.dumpSchema;
    1139         320 :     ropt->dumpStatistics = dopt.dumpStatistics;
    1140         320 :     ropt->if_exists = dopt.if_exists;
    1141         320 :     ropt->column_inserts = dopt.column_inserts;
    1142         320 :     ropt->dumpSections = dopt.dumpSections;
    1143         320 :     ropt->aclsSkip = dopt.aclsSkip;
    1144         320 :     ropt->superuser = dopt.outputSuperuser;
    1145         320 :     ropt->createDB = dopt.outputCreateDB;
    1146         320 :     ropt->noOwner = dopt.outputNoOwner;
    1147         320 :     ropt->noTableAm = dopt.outputNoTableAm;
    1148         320 :     ropt->noTablespace = dopt.outputNoTablespaces;
    1149         320 :     ropt->disable_triggers = dopt.disable_triggers;
    1150         320 :     ropt->use_setsessauth = dopt.use_setsessauth;
    1151         320 :     ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
    1152         320 :     ropt->dump_inserts = dopt.dump_inserts;
    1153         320 :     ropt->no_comments = dopt.no_comments;
    1154         320 :     ropt->no_publications = dopt.no_publications;
    1155         320 :     ropt->no_security_labels = dopt.no_security_labels;
    1156         320 :     ropt->no_subscriptions = dopt.no_subscriptions;
    1157         320 :     ropt->lockWaitTimeout = dopt.lockWaitTimeout;
    1158         320 :     ropt->include_everything = dopt.include_everything;
    1159         320 :     ropt->enable_row_security = dopt.enable_row_security;
    1160         320 :     ropt->sequence_data = dopt.sequence_data;
    1161         320 :     ropt->binary_upgrade = dopt.binary_upgrade;
    1162             : 
    1163         320 :     ropt->compression_spec = compression_spec;
    1164             : 
    1165         320 :     ropt->suppressDumpWarnings = true;   /* We've already shown them */
    1166             : 
    1167         320 :     SetArchiveOptions(fout, &dopt, ropt);
    1168             : 
    1169             :     /* Mark which entries should be output */
    1170         320 :     ProcessArchiveRestoreOptions(fout);
    1171             : 
    1172             :     /*
    1173             :      * The archive's TOC entries are now marked as to which ones will actually
    1174             :      * be output, so we can set up their dependency lists properly. This isn't
    1175             :      * necessary for plain-text output, though.
    1176             :      */
    1177         320 :     if (!plainText)
    1178          66 :         BuildArchiveDependencies(fout);
    1179             : 
    1180             :     /*
    1181             :      * And finally we can do the actual output.
    1182             :      *
    1183             :      * Note: for non-plain-text output formats, the output file is written
    1184             :      * inside CloseArchive().  This is, um, bizarre; but not worth changing
    1185             :      * right now.
    1186             :      */
    1187         320 :     if (plainText)
    1188         254 :         RestoreArchive(fout);
    1189             : 
    1190         318 :     CloseArchive(fout);
    1191             : 
    1192         318 :     exit_nicely(0);
    1193             : }
    1194             : 
    1195             : 
    1196             : static void
    1197           2 : help(const char *progname)
    1198             : {
    1199           2 :     printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
    1200           2 :     printf(_("Usage:\n"));
    1201           2 :     printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
    1202             : 
    1203           2 :     printf(_("\nGeneral options:\n"));
    1204           2 :     printf(_("  -f, --file=FILENAME          output file or directory name\n"));
    1205           2 :     printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
    1206             :              "                               plain text (default))\n"));
    1207           2 :     printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
    1208           2 :     printf(_("  -v, --verbose                verbose mode\n"));
    1209           2 :     printf(_("  -V, --version                output version information, then exit\n"));
    1210           2 :     printf(_("  -Z, --compress=METHOD[:DETAIL]\n"
    1211             :              "                               compress as specified\n"));
    1212           2 :     printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
    1213           2 :     printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
    1214           2 :     printf(_("  --sync-method=METHOD         set method for syncing files to disk\n"));
    1215           2 :     printf(_("  -?, --help                   show this help, then exit\n"));
    1216             : 
    1217           2 :     printf(_("\nOptions controlling the output content:\n"));
    1218           2 :     printf(_("  -a, --data-only              dump only the data, not the schema or statistics\n"));
    1219           2 :     printf(_("  -b, --large-objects          include large objects in dump\n"));
    1220           2 :     printf(_("  --blobs                      (same as --large-objects, deprecated)\n"));
    1221           2 :     printf(_("  -B, --no-large-objects       exclude large objects in dump\n"));
    1222           2 :     printf(_("  --no-blobs                   (same as --no-large-objects, deprecated)\n"));
    1223           2 :     printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
    1224           2 :     printf(_("  -C, --create                 include commands to create database in dump\n"));
    1225           2 :     printf(_("  -e, --extension=PATTERN      dump the specified extension(s) only\n"));
    1226           2 :     printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
    1227           2 :     printf(_("  -n, --schema=PATTERN         dump the specified schema(s) only\n"));
    1228           2 :     printf(_("  -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
    1229           2 :     printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
    1230             :              "                               plain-text format\n"));
    1231           2 :     printf(_("  -s, --schema-only            dump only the schema, no data or statistics\n"));
    1232           2 :     printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
    1233           2 :     printf(_("  -t, --table=PATTERN          dump only the specified table(s)\n"));
    1234           2 :     printf(_("  -T, --exclude-table=PATTERN  do NOT dump the specified table(s)\n"));
    1235           2 :     printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
    1236           2 :     printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
    1237           2 :     printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
    1238           2 :     printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
    1239           2 :     printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
    1240           2 :     printf(_("  --enable-row-security        enable row security (dump only content user has\n"
    1241             :              "                               access to)\n"));
    1242           2 :     printf(_("  --exclude-extension=PATTERN  do NOT dump the specified extension(s)\n"));
    1243           2 :     printf(_("  --exclude-table-and-children=PATTERN\n"
    1244             :              "                               do NOT dump the specified table(s), including\n"
    1245             :              "                               child and partition tables\n"));
    1246           2 :     printf(_("  --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
    1247           2 :     printf(_("  --exclude-table-data-and-children=PATTERN\n"
    1248             :              "                               do NOT dump data for the specified table(s),\n"
    1249             :              "                               including child and partition tables\n"));
    1250           2 :     printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
    1251           2 :     printf(_("  --filter=FILENAME            include or exclude objects and data from dump\n"
    1252             :              "                               based on expressions in FILENAME\n"));
    1253           2 :     printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
    1254           2 :     printf(_("  --include-foreign-data=PATTERN\n"
    1255             :              "                               include data of foreign tables on foreign\n"
    1256             :              "                               servers matching PATTERN\n"));
    1257           2 :     printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
    1258           2 :     printf(_("  --load-via-partition-root    load partitions via the root table\n"));
    1259           2 :     printf(_("  --no-comments                do not dump comment commands\n"));
    1260           2 :     printf(_("  --no-data                    do not dump data\n"));
    1261           2 :     printf(_("  --no-publications            do not dump publications\n"));
    1262           2 :     printf(_("  --no-schema                  do not dump schema\n"));
    1263           2 :     printf(_("  --no-security-labels         do not dump security label assignments\n"));
    1264           2 :     printf(_("  --no-statistics              do not dump statistics\n"));
    1265           2 :     printf(_("  --no-subscriptions           do not dump subscriptions\n"));
    1266           2 :     printf(_("  --no-table-access-method     do not dump table access methods\n"));
    1267           2 :     printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
    1268           2 :     printf(_("  --no-toast-compression       do not dump TOAST compression methods\n"));
    1269           2 :     printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
    1270           2 :     printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
    1271           2 :     printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
    1272           2 :     printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
    1273           2 :     printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
    1274           2 :     printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
    1275           2 :     printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
    1276           2 :     printf(_("  --statistics-only            dump only the statistics, not schema or data\n"));
    1277           2 :     printf(_("  --strict-names               require table and/or schema include patterns to\n"
    1278             :              "                               match at least one entity each\n"));
    1279           2 :     printf(_("  --table-and-children=PATTERN dump only the specified table(s), including\n"
    1280             :              "                               child and partition tables\n"));
    1281           2 :     printf(_("  --use-set-session-authorization\n"
    1282             :              "                               use SET SESSION AUTHORIZATION commands instead of\n"
    1283             :              "                               ALTER OWNER commands to set ownership\n"));
    1284             : 
    1285           2 :     printf(_("\nConnection options:\n"));
    1286           2 :     printf(_("  -d, --dbname=DBNAME      database to dump\n"));
    1287           2 :     printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
    1288           2 :     printf(_("  -p, --port=PORT          database server port number\n"));
    1289           2 :     printf(_("  -U, --username=NAME      connect as specified database user\n"));
    1290           2 :     printf(_("  -w, --no-password        never prompt for password\n"));
    1291           2 :     printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
    1292           2 :     printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
    1293             : 
    1294           2 :     printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
    1295             :              "variable value is used.\n\n"));
    1296           2 :     printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    1297           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    1298           2 : }
    1299             : 
    1300             : static void
    1301         386 : setup_connection(Archive *AH, const char *dumpencoding,
    1302             :                  const char *dumpsnapshot, char *use_role)
    1303             : {
    1304         386 :     DumpOptions *dopt = AH->dopt;
    1305         386 :     PGconn     *conn = GetConnection(AH);
    1306             :     const char *std_strings;
    1307             : 
    1308         386 :     PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
    1309             : 
    1310             :     /*
    1311             :      * Set the client encoding if requested.
    1312             :      */
    1313         386 :     if (dumpencoding)
    1314             :     {
    1315          36 :         if (PQsetClientEncoding(conn, dumpencoding) < 0)
    1316           0 :             pg_fatal("invalid client encoding \"%s\" specified",
    1317             :                      dumpencoding);
    1318             :     }
    1319             : 
    1320             :     /*
    1321             :      * Get the active encoding and the standard_conforming_strings setting, so
    1322             :      * we know how to escape strings.
    1323             :      */
    1324         386 :     AH->encoding = PQclientEncoding(conn);
    1325         386 :     setFmtEncoding(AH->encoding);
    1326             : 
    1327         386 :     std_strings = PQparameterStatus(conn, "standard_conforming_strings");
    1328         386 :     AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
    1329             : 
    1330             :     /*
    1331             :      * Set the role if requested.  In a parallel dump worker, we'll be passed
    1332             :      * use_role == NULL, but AH->use_role is already set (if user specified it
    1333             :      * originally) and we should use that.
    1334             :      */
    1335         386 :     if (!use_role && AH->use_role)
    1336           4 :         use_role = AH->use_role;
    1337             : 
    1338             :     /* Set the role if requested */
    1339         386 :     if (use_role)
    1340             :     {
    1341          10 :         PQExpBuffer query = createPQExpBuffer();
    1342             : 
    1343          10 :         appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
    1344          10 :         ExecuteSqlStatement(AH, query->data);
    1345          10 :         destroyPQExpBuffer(query);
    1346             : 
    1347             :         /* save it for possible later use by parallel workers */
    1348          10 :         if (!AH->use_role)
    1349           6 :             AH->use_role = pg_strdup(use_role);
    1350             :     }
    1351             : 
    1352             :     /* Set the datestyle to ISO to ensure the dump's portability */
    1353         386 :     ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
    1354             : 
    1355             :     /* Likewise, avoid using sql_standard intervalstyle */
    1356         386 :     ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
    1357             : 
    1358             :     /*
    1359             :      * Use an explicitly specified extra_float_digits if it has been provided.
    1360             :      * Otherwise, set extra_float_digits so that we can dump float data
    1361             :      * exactly (given correctly implemented float I/O code, anyway).
    1362             :      */
    1363         386 :     if (have_extra_float_digits)
    1364             :     {
    1365           0 :         PQExpBuffer q = createPQExpBuffer();
    1366             : 
    1367           0 :         appendPQExpBuffer(q, "SET extra_float_digits TO %d",
    1368             :                           extra_float_digits);
    1369           0 :         ExecuteSqlStatement(AH, q->data);
    1370           0 :         destroyPQExpBuffer(q);
    1371             :     }
    1372             :     else
    1373         386 :         ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
    1374             : 
    1375             :     /*
    1376             :      * Disable synchronized scanning, to prevent unpredictable changes in row
    1377             :      * ordering across a dump and reload.
    1378             :      */
    1379         386 :     ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
    1380             : 
    1381             :     /*
    1382             :      * Disable timeouts if supported.
    1383             :      */
    1384         386 :     ExecuteSqlStatement(AH, "SET statement_timeout = 0");
    1385         386 :     if (AH->remoteVersion >= 90300)
    1386         386 :         ExecuteSqlStatement(AH, "SET lock_timeout = 0");
    1387         386 :     if (AH->remoteVersion >= 90600)
    1388         386 :         ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
    1389         386 :     if (AH->remoteVersion >= 170000)
    1390         386 :         ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
    1391             : 
    1392             :     /*
    1393             :      * Quote all identifiers, if requested.
    1394             :      */
    1395         386 :     if (quote_all_identifiers)
    1396          28 :         ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
    1397             : 
    1398             :     /*
    1399             :      * Adjust row-security mode, if supported.
    1400             :      */
    1401         386 :     if (AH->remoteVersion >= 90500)
    1402             :     {
    1403         386 :         if (dopt->enable_row_security)
    1404           0 :             ExecuteSqlStatement(AH, "SET row_security = on");
    1405             :         else
    1406         386 :             ExecuteSqlStatement(AH, "SET row_security = off");
    1407             :     }
    1408             : 
    1409             :     /*
    1410             :      * For security reasons, we restrict the expansion of non-system views and
    1411             :      * access to foreign tables during the pg_dump process. This restriction
    1412             :      * is adjusted when dumping foreign table data.
    1413             :      */
    1414         386 :     set_restrict_relation_kind(AH, "view, foreign-table");
    1415             : 
    1416             :     /*
    1417             :      * Initialize prepared-query state to "nothing prepared".  We do this here
    1418             :      * so that a parallel dump worker will have its own state.
    1419             :      */
    1420         386 :     AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
    1421             : 
    1422             :     /*
    1423             :      * Start transaction-snapshot mode transaction to dump consistent data.
    1424             :      */
    1425         386 :     ExecuteSqlStatement(AH, "BEGIN");
    1426             : 
    1427             :     /*
    1428             :      * To support the combination of serializable_deferrable with the jobs
    1429             :      * option we use REPEATABLE READ for the worker connections that are
    1430             :      * passed a snapshot.  As long as the snapshot is acquired in a
    1431             :      * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
    1432             :      * REPEATABLE READ transaction provides the appropriate integrity
    1433             :      * guarantees.  This is a kluge, but safe for back-patching.
    1434             :      */
    1435         386 :     if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
    1436           0 :         ExecuteSqlStatement(AH,
    1437             :                             "SET TRANSACTION ISOLATION LEVEL "
    1438             :                             "SERIALIZABLE, READ ONLY, DEFERRABLE");
    1439             :     else
    1440         386 :         ExecuteSqlStatement(AH,
    1441             :                             "SET TRANSACTION ISOLATION LEVEL "
    1442             :                             "REPEATABLE READ, READ ONLY");
    1443             : 
    1444             :     /*
    1445             :      * If user specified a snapshot to use, select that.  In a parallel dump
    1446             :      * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
    1447             :      * is already set (if the server can handle it) and we should use that.
    1448             :      */
    1449         386 :     if (dumpsnapshot)
    1450           0 :         AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
    1451             : 
    1452         386 :     if (AH->sync_snapshot_id)
    1453             :     {
    1454          32 :         PQExpBuffer query = createPQExpBuffer();
    1455             : 
    1456          32 :         appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
    1457          32 :         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
    1458          32 :         ExecuteSqlStatement(AH, query->data);
    1459          32 :         destroyPQExpBuffer(query);
    1460             :     }
    1461         354 :     else if (AH->numWorkers > 1)
    1462             :     {
    1463          16 :         if (AH->isStandby && AH->remoteVersion < 100000)
    1464           0 :             pg_fatal("parallel dumps from standby servers are not supported by this server version");
    1465          16 :         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
    1466             :     }
    1467         386 : }
    1468             : 
    1469             : /* Set up connection for a parallel worker process */
    1470             : static void
    1471          32 : setupDumpWorker(Archive *AH)
    1472             : {
    1473             :     /*
    1474             :      * We want to re-select all the same values the leader connection is
    1475             :      * using.  We'll have inherited directly-usable values in
    1476             :      * AH->sync_snapshot_id and AH->use_role, but we need to translate the
    1477             :      * inherited encoding value back to a string to pass to setup_connection.
    1478             :      */
    1479          32 :     setup_connection(AH,
    1480             :                      pg_encoding_to_char(AH->encoding),
    1481             :                      NULL,
    1482             :                      NULL);
    1483          32 : }
    1484             : 
    1485             : static char *
    1486          16 : get_synchronized_snapshot(Archive *fout)
    1487             : {
    1488          16 :     char       *query = "SELECT pg_catalog.pg_export_snapshot()";
    1489             :     char       *result;
    1490             :     PGresult   *res;
    1491             : 
    1492          16 :     res = ExecuteSqlQueryForSingleRow(fout, query);
    1493          16 :     result = pg_strdup(PQgetvalue(res, 0, 0));
    1494          16 :     PQclear(res);
    1495             : 
    1496          16 :     return result;
    1497             : }
    1498             : 
    1499             : static ArchiveFormat
    1500         372 : parseArchiveFormat(const char *format, ArchiveMode *mode)
    1501             : {
    1502             :     ArchiveFormat archiveFormat;
    1503             : 
    1504         372 :     *mode = archModeWrite;
    1505             : 
    1506         372 :     if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
    1507             :     {
    1508             :         /* This is used by pg_dumpall, and is not documented */
    1509          86 :         archiveFormat = archNull;
    1510          86 :         *mode = archModeAppend;
    1511             :     }
    1512         286 :     else if (pg_strcasecmp(format, "c") == 0)
    1513           2 :         archiveFormat = archCustom;
    1514         284 :     else if (pg_strcasecmp(format, "custom") == 0)
    1515          40 :         archiveFormat = archCustom;
    1516         244 :     else if (pg_strcasecmp(format, "d") == 0)
    1517           4 :         archiveFormat = archDirectory;
    1518         240 :     else if (pg_strcasecmp(format, "directory") == 0)
    1519          16 :         archiveFormat = archDirectory;
    1520         224 :     else if (pg_strcasecmp(format, "p") == 0)
    1521         210 :         archiveFormat = archNull;
    1522          14 :     else if (pg_strcasecmp(format, "plain") == 0)
    1523           6 :         archiveFormat = archNull;
    1524           8 :     else if (pg_strcasecmp(format, "t") == 0)
    1525           2 :         archiveFormat = archTar;
    1526           6 :     else if (pg_strcasecmp(format, "tar") == 0)
    1527           4 :         archiveFormat = archTar;
    1528             :     else
    1529           2 :         pg_fatal("invalid output format \"%s\" specified", format);
    1530         370 :     return archiveFormat;
    1531             : }
    1532             : 
    1533             : /*
    1534             :  * Find the OIDs of all schemas matching the given list of patterns,
    1535             :  * and append them to the given OID list.
    1536             :  */
    1537             : static void
    1538         376 : expand_schema_name_patterns(Archive *fout,
    1539             :                             SimpleStringList *patterns,
    1540             :                             SimpleOidList *oids,
    1541             :                             bool strict_names)
    1542             : {
    1543             :     PQExpBuffer query;
    1544             :     PGresult   *res;
    1545             :     SimpleStringListCell *cell;
    1546             :     int         i;
    1547             : 
    1548         376 :     if (patterns->head == NULL)
    1549         334 :         return;                 /* nothing to do */
    1550             : 
    1551          42 :     query = createPQExpBuffer();
    1552             : 
    1553             :     /*
    1554             :      * The loop below runs multiple SELECTs might sometimes result in
    1555             :      * duplicate entries in the OID list, but we don't care.
    1556             :      */
    1557             : 
    1558          72 :     for (cell = patterns->head; cell; cell = cell->next)
    1559             :     {
    1560             :         PQExpBufferData dbbuf;
    1561             :         int         dotcnt;
    1562             : 
    1563          42 :         appendPQExpBufferStr(query,
    1564             :                              "SELECT oid FROM pg_catalog.pg_namespace n\n");
    1565          42 :         initPQExpBuffer(&dbbuf);
    1566          42 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1567             :                               false, NULL, "n.nspname", NULL, NULL, &dbbuf,
    1568             :                               &dotcnt);
    1569          42 :         if (dotcnt > 1)
    1570           4 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1571             :                      cell->val);
    1572          38 :         else if (dotcnt == 1)
    1573           6 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1574          32 :         termPQExpBuffer(&dbbuf);
    1575             : 
    1576          32 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1577          32 :         if (strict_names && PQntuples(res) == 0)
    1578           2 :             pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
    1579             : 
    1580          58 :         for (i = 0; i < PQntuples(res); i++)
    1581             :         {
    1582          28 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1583             :         }
    1584             : 
    1585          30 :         PQclear(res);
    1586          30 :         resetPQExpBuffer(query);
    1587             :     }
    1588             : 
    1589          30 :     destroyPQExpBuffer(query);
    1590             : }
    1591             : 
    1592             : /*
    1593             :  * Find the OIDs of all extensions matching the given list of patterns,
    1594             :  * and append them to the given OID list.
    1595             :  */
    1596             : static void
    1597         332 : expand_extension_name_patterns(Archive *fout,
    1598             :                                SimpleStringList *patterns,
    1599             :                                SimpleOidList *oids,
    1600             :                                bool strict_names)
    1601             : {
    1602             :     PQExpBuffer query;
    1603             :     PGresult   *res;
    1604             :     SimpleStringListCell *cell;
    1605             :     int         i;
    1606             : 
    1607         332 :     if (patterns->head == NULL)
    1608         318 :         return;                 /* nothing to do */
    1609             : 
    1610          14 :     query = createPQExpBuffer();
    1611             : 
    1612             :     /*
    1613             :      * The loop below runs multiple SELECTs might sometimes result in
    1614             :      * duplicate entries in the OID list, but we don't care.
    1615             :      */
    1616          28 :     for (cell = patterns->head; cell; cell = cell->next)
    1617             :     {
    1618             :         int         dotcnt;
    1619             : 
    1620          14 :         appendPQExpBufferStr(query,
    1621             :                              "SELECT oid FROM pg_catalog.pg_extension e\n");
    1622          14 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1623             :                               false, NULL, "e.extname", NULL, NULL, NULL,
    1624             :                               &dotcnt);
    1625          14 :         if (dotcnt > 0)
    1626           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1627             :                      cell->val);
    1628             : 
    1629          14 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1630          14 :         if (strict_names && PQntuples(res) == 0)
    1631           0 :             pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
    1632             : 
    1633          26 :         for (i = 0; i < PQntuples(res); i++)
    1634             :         {
    1635          12 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1636             :         }
    1637             : 
    1638          14 :         PQclear(res);
    1639          14 :         resetPQExpBuffer(query);
    1640             :     }
    1641             : 
    1642          14 :     destroyPQExpBuffer(query);
    1643             : }
    1644             : 
    1645             : /*
    1646             :  * Find the OIDs of all foreign servers matching the given list of patterns,
    1647             :  * and append them to the given OID list.
    1648             :  */
    1649             : static void
    1650         326 : expand_foreign_server_name_patterns(Archive *fout,
    1651             :                                     SimpleStringList *patterns,
    1652             :                                     SimpleOidList *oids)
    1653             : {
    1654             :     PQExpBuffer query;
    1655             :     PGresult   *res;
    1656             :     SimpleStringListCell *cell;
    1657             :     int         i;
    1658             : 
    1659         326 :     if (patterns->head == NULL)
    1660         320 :         return;                 /* nothing to do */
    1661             : 
    1662           6 :     query = createPQExpBuffer();
    1663             : 
    1664             :     /*
    1665             :      * The loop below runs multiple SELECTs might sometimes result in
    1666             :      * duplicate entries in the OID list, but we don't care.
    1667             :      */
    1668             : 
    1669          10 :     for (cell = patterns->head; cell; cell = cell->next)
    1670             :     {
    1671             :         int         dotcnt;
    1672             : 
    1673           6 :         appendPQExpBufferStr(query,
    1674             :                              "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
    1675           6 :         processSQLNamePattern(GetConnection(fout), query, cell->val, false,
    1676             :                               false, NULL, "s.srvname", NULL, NULL, NULL,
    1677             :                               &dotcnt);
    1678           6 :         if (dotcnt > 0)
    1679           0 :             pg_fatal("improper qualified name (too many dotted names): %s",
    1680             :                      cell->val);
    1681             : 
    1682           6 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1683           6 :         if (PQntuples(res) == 0)
    1684           2 :             pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
    1685             : 
    1686           8 :         for (i = 0; i < PQntuples(res); i++)
    1687           4 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1688             : 
    1689           4 :         PQclear(res);
    1690           4 :         resetPQExpBuffer(query);
    1691             :     }
    1692             : 
    1693           4 :     destroyPQExpBuffer(query);
    1694             : }
    1695             : 
    1696             : /*
    1697             :  * Find the OIDs of all tables matching the given list of patterns,
    1698             :  * and append them to the given OID list. See also expand_dbname_patterns()
    1699             :  * in pg_dumpall.c
    1700             :  */
    1701             : static void
    1702        1974 : expand_table_name_patterns(Archive *fout,
    1703             :                            SimpleStringList *patterns, SimpleOidList *oids,
    1704             :                            bool strict_names, bool with_child_tables)
    1705             : {
    1706             :     PQExpBuffer query;
    1707             :     PGresult   *res;
    1708             :     SimpleStringListCell *cell;
    1709             :     int         i;
    1710             : 
    1711        1974 :     if (patterns->head == NULL)
    1712        1916 :         return;                 /* nothing to do */
    1713             : 
    1714          58 :     query = createPQExpBuffer();
    1715             : 
    1716             :     /*
    1717             :      * this might sometimes result in duplicate entries in the OID list, but
    1718             :      * we don't care.
    1719             :      */
    1720             : 
    1721         118 :     for (cell = patterns->head; cell; cell = cell->next)
    1722             :     {
    1723             :         PQExpBufferData dbbuf;
    1724             :         int         dotcnt;
    1725             : 
    1726             :         /*
    1727             :          * Query must remain ABSOLUTELY devoid of unqualified names.  This
    1728             :          * would be unnecessary given a pg_table_is_visible() variant taking a
    1729             :          * search_path argument.
    1730             :          *
    1731             :          * For with_child_tables, we start with the basic query's results and
    1732             :          * recursively search the inheritance tree to add child tables.
    1733             :          */
    1734          70 :         if (with_child_tables)
    1735             :         {
    1736          12 :             appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
    1737             :         }
    1738             : 
    1739          70 :         appendPQExpBuffer(query,
    1740             :                           "SELECT c.oid"
    1741             :                           "\nFROM pg_catalog.pg_class c"
    1742             :                           "\n     LEFT JOIN pg_catalog.pg_namespace n"
    1743             :                           "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
    1744             :                           "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
    1745             :                           "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
    1746             :                           RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
    1747             :                           RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
    1748             :                           RELKIND_PARTITIONED_TABLE);
    1749          70 :         initPQExpBuffer(&dbbuf);
    1750          70 :         processSQLNamePattern(GetConnection(fout), query, cell->val, true,
    1751             :                               false, "n.nspname", "c.relname", NULL,
    1752             :                               "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
    1753             :                               &dotcnt);
    1754          70 :         if (dotcnt > 2)
    1755           2 :             pg_fatal("improper relation name (too many dotted names): %s",
    1756             :                      cell->val);
    1757          68 :         else if (dotcnt == 2)
    1758           4 :             prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
    1759          64 :         termPQExpBuffer(&dbbuf);
    1760             : 
    1761          64 :         if (with_child_tables)
    1762             :         {
    1763          12 :             appendPQExpBuffer(query, "UNION"
    1764             :                               "\nSELECT i.inhrelid"
    1765             :                               "\nFROM partition_tree p"
    1766             :                               "\n     JOIN pg_catalog.pg_inherits i"
    1767             :                               "\n     ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
    1768             :                               "\n)"
    1769             :                               "\nSELECT relid FROM partition_tree");
    1770             :         }
    1771             : 
    1772          64 :         ExecuteSqlStatement(fout, "RESET search_path");
    1773          64 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    1774          64 :         PQclear(ExecuteSqlQueryForSingleRow(fout,
    1775             :                                             ALWAYS_SECURE_SEARCH_PATH_SQL));
    1776          64 :         if (strict_names && PQntuples(res) == 0)
    1777           4 :             pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
    1778             : 
    1779         148 :         for (i = 0; i < PQntuples(res); i++)
    1780             :         {
    1781          88 :             simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
    1782             :         }
    1783             : 
    1784          60 :         PQclear(res);
    1785          60 :         resetPQExpBuffer(query);
    1786             :     }
    1787             : 
    1788          48 :     destroyPQExpBuffer(query);
    1789             : }
    1790             : 
    1791             : /*
    1792             :  * Verifies that the connected database name matches the given database name,
    1793             :  * and if not, dies with an error about the given pattern.
    1794             :  *
    1795             :  * The 'dbname' argument should be a literal name parsed from 'pattern'.
    1796             :  */
    1797             : static void
    1798          10 : prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
    1799             : {
    1800             :     const char *db;
    1801             : 
    1802          10 :     db = PQdb(conn);
    1803          10 :     if (db == NULL)
    1804           0 :         pg_fatal("You are currently not connected to a database.");
    1805             : 
    1806          10 :     if (strcmp(db, dbname) != 0)
    1807          10 :         pg_fatal("cross-database references are not implemented: %s",
    1808             :                  pattern);
    1809           0 : }
    1810             : 
    1811             : /*
    1812             :  * checkExtensionMembership
    1813             :  *      Determine whether object is an extension member, and if so,
    1814             :  *      record an appropriate dependency and set the object's dump flag.
    1815             :  *
    1816             :  * It's important to call this for each object that could be an extension
    1817             :  * member.  Generally, we integrate this with determining the object's
    1818             :  * to-be-dumped-ness, since extension membership overrides other rules for that.
    1819             :  *
    1820             :  * Returns true if object is an extension member, else false.
    1821             :  */
    1822             : static bool
    1823      999650 : checkExtensionMembership(DumpableObject *dobj, Archive *fout)
    1824             : {
    1825      999650 :     ExtensionInfo *ext = findOwningExtension(dobj->catId);
    1826             : 
    1827      999650 :     if (ext == NULL)
    1828      998234 :         return false;
    1829             : 
    1830        1416 :     dobj->ext_member = true;
    1831             : 
    1832             :     /* Record dependency so that getDependencies needn't deal with that */
    1833        1416 :     addObjectDependency(dobj, ext->dobj.dumpId);
    1834             : 
    1835             :     /*
    1836             :      * In 9.6 and above, mark the member object to have any non-initial ACLs
    1837             :      * dumped.  (Any initial ACLs will be removed later, using data from
    1838             :      * pg_init_privs, so that we'll dump only the delta from the extension's
    1839             :      * initial setup.)
    1840             :      *
    1841             :      * Prior to 9.6, we do not include any extension member components.
    1842             :      *
    1843             :      * In binary upgrades, we still dump all components of the members
    1844             :      * individually, since the idea is to exactly reproduce the database
    1845             :      * contents rather than replace the extension contents with something
    1846             :      * different.
    1847             :      *
    1848             :      * Note: it might be interesting someday to implement storage and delta
    1849             :      * dumping of extension members' RLS policies and/or security labels.
    1850             :      * However there is a pitfall for RLS policies: trying to dump them
    1851             :      * requires getting a lock on their tables, and the calling user might not
    1852             :      * have privileges for that.  We need no lock to examine a table's ACLs,
    1853             :      * so the current feature doesn't have a problem of that sort.
    1854             :      */
    1855        1416 :     if (fout->dopt->binary_upgrade)
    1856         168 :         dobj->dump = ext->dobj.dump;
    1857             :     else
    1858             :     {
    1859        1248 :         if (fout->remoteVersion < 90600)
    1860           0 :             dobj->dump = DUMP_COMPONENT_NONE;
    1861             :         else
    1862        1248 :             dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
    1863             :     }
    1864             : 
    1865        1416 :     return true;
    1866             : }
    1867             : 
    1868             : /*
    1869             :  * selectDumpableNamespace: policy-setting subroutine
    1870             :  *      Mark a namespace as to be dumped or not
    1871             :  */
    1872             : static void
    1873        2620 : selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
    1874             : {
    1875             :     /*
    1876             :      * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
    1877             :      * and (for --clean) a DROP SCHEMA statement.  (In the absence of
    1878             :      * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
    1879             :      */
    1880        2620 :     nsinfo->create = true;
    1881             : 
    1882             :     /*
    1883             :      * If specific tables are being dumped, do not dump any complete
    1884             :      * namespaces. If specific namespaces are being dumped, dump just those
    1885             :      * namespaces. Otherwise, dump all non-system namespaces.
    1886             :      */
    1887        2620 :     if (table_include_oids.head != NULL)
    1888         100 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1889        2520 :     else if (schema_include_oids.head != NULL)
    1890         358 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
    1891         358 :             simple_oid_list_member(&schema_include_oids,
    1892             :                                    nsinfo->dobj.catId.oid) ?
    1893         358 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1894        2162 :     else if (fout->remoteVersion >= 90600 &&
    1895        2162 :              strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
    1896             :     {
    1897             :         /*
    1898             :          * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
    1899             :          * they are interesting (and not the original ACLs which were set at
    1900             :          * initdb time, see pg_init_privs).
    1901             :          */
    1902         278 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
    1903             :     }
    1904        1884 :     else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
    1905         870 :              strcmp(nsinfo->dobj.name, "information_schema") == 0)
    1906             :     {
    1907             :         /* Other system schemas don't get dumped */
    1908        1292 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1909             :     }
    1910         592 :     else if (strcmp(nsinfo->dobj.name, "public") == 0)
    1911             :     {
    1912             :         /*
    1913             :          * The public schema is a strange beast that sits in a sort of
    1914             :          * no-mans-land between being a system object and a user object.
    1915             :          * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
    1916             :          * a comment and an indication of ownership.  If the owner is the
    1917             :          * default, omit that superfluous DUMP_COMPONENT_DEFINITION.  Before
    1918             :          * v15, the default owner was BOOTSTRAP_SUPERUSERID.
    1919             :          */
    1920         270 :         nsinfo->create = false;
    1921         270 :         nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1922         270 :         if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
    1923         182 :             nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
    1924         270 :         nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
    1925             : 
    1926             :         /*
    1927             :          * Also, make like it has a comment even if it doesn't; this is so
    1928             :          * that we'll emit a command to drop the comment, if appropriate.
    1929             :          * (Without this, we'd not call dumpCommentExtended for it.)
    1930             :          */
    1931         270 :         nsinfo->dobj.components |= DUMP_COMPONENT_COMMENT;
    1932             :     }
    1933             :     else
    1934         322 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
    1935             : 
    1936             :     /*
    1937             :      * In any case, a namespace can be excluded by an exclusion switch
    1938             :      */
    1939        3512 :     if (nsinfo->dobj.dump_contains &&
    1940         892 :         simple_oid_list_member(&schema_exclude_oids,
    1941             :                                nsinfo->dobj.catId.oid))
    1942           6 :         nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1943             : 
    1944             :     /*
    1945             :      * If the schema belongs to an extension, allow extension membership to
    1946             :      * override the dump decision for the schema itself.  However, this does
    1947             :      * not change dump_contains, so this won't change what we do with objects
    1948             :      * within the schema.  (If they belong to the extension, they'll get
    1949             :      * suppressed by it, otherwise not.)
    1950             :      */
    1951        2620 :     (void) checkExtensionMembership(&nsinfo->dobj, fout);
    1952        2620 : }
    1953             : 
    1954             : /*
    1955             :  * selectDumpableTable: policy-setting subroutine
    1956             :  *      Mark a table as to be dumped or not
    1957             :  */
    1958             : static void
    1959       84892 : selectDumpableTable(TableInfo *tbinfo, Archive *fout)
    1960             : {
    1961       84892 :     if (checkExtensionMembership(&tbinfo->dobj, fout))
    1962         450 :         return;                 /* extension membership overrides all else */
    1963             : 
    1964             :     /*
    1965             :      * If specific tables are being dumped, dump just those tables; else, dump
    1966             :      * according to the parent namespace's dump flag.
    1967             :      */
    1968       84442 :     if (table_include_oids.head != NULL)
    1969       10128 :         tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
    1970             :                                                    tbinfo->dobj.catId.oid) ?
    1971        5064 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    1972             :     else
    1973       79378 :         tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
    1974             : 
    1975             :     /*
    1976             :      * In any case, a table can be excluded by an exclusion switch
    1977             :      */
    1978      137234 :     if (tbinfo->dobj.dump &&
    1979       52792 :         simple_oid_list_member(&table_exclude_oids,
    1980             :                                tbinfo->dobj.catId.oid))
    1981          24 :         tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
    1982             : }
    1983             : 
    1984             : /*
    1985             :  * selectDumpableType: policy-setting subroutine
    1986             :  *      Mark a type as to be dumped or not
    1987             :  *
    1988             :  * If it's a table's rowtype or an autogenerated array type, we also apply a
    1989             :  * special type code to facilitate sorting into the desired order.  (We don't
    1990             :  * want to consider those to be ordinary types because that would bring tables
    1991             :  * up into the datatype part of the dump order.)  We still set the object's
    1992             :  * dump flag; that's not going to cause the dummy type to be dumped, but we
    1993             :  * need it so that casts involving such types will be dumped correctly -- see
    1994             :  * dumpCast.  This means the flag should be set the same as for the underlying
    1995             :  * object (the table or base type).
    1996             :  */
    1997             : static void
    1998      231988 : selectDumpableType(TypeInfo *tyinfo, Archive *fout)
    1999             : {
    2000             :     /* skip complex types, except for standalone composite types */
    2001      231988 :     if (OidIsValid(tyinfo->typrelid) &&
    2002       83462 :         tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
    2003             :     {
    2004       83094 :         TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
    2005             : 
    2006       83094 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2007       83094 :         if (tytable != NULL)
    2008       83094 :             tyinfo->dobj.dump = tytable->dobj.dump;
    2009             :         else
    2010           0 :             tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
    2011       83094 :         return;
    2012             :     }
    2013             : 
    2014             :     /* skip auto-generated array and multirange types */
    2015      148894 :     if (tyinfo->isArray || tyinfo->isMultirange)
    2016             :     {
    2017      113492 :         tyinfo->dobj.objType = DO_DUMMY_TYPE;
    2018             : 
    2019             :         /*
    2020             :          * Fall through to set the dump flag; we assume that the subsequent
    2021             :          * rules will do the same thing as they would for the array's base
    2022             :          * type or multirange's range type.  (We cannot reliably look up the
    2023             :          * base type here, since getTypes may not have processed it yet.)
    2024             :          */
    2025             :     }
    2026             : 
    2027      148894 :     if (checkExtensionMembership(&tyinfo->dobj, fout))
    2028         300 :         return;                 /* extension membership overrides all else */
    2029             : 
    2030             :     /* Dump based on if the contents of the namespace are being dumped */
    2031      148594 :     tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
    2032             : }
    2033             : 
    2034             : /*
    2035             :  * selectDumpableDefaultACL: policy-setting subroutine
    2036             :  *      Mark a default ACL as to be dumped or not
    2037             :  *
    2038             :  * For per-schema default ACLs, dump if the schema is to be dumped.
    2039             :  * Otherwise dump if we are dumping "everything".  Note that dumpSchema
    2040             :  * and aclsSkip are checked separately.
    2041             :  */
    2042             : static void
    2043         376 : selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
    2044             : {
    2045             :     /* Default ACLs can't be extension members */
    2046             : 
    2047         376 :     if (dinfo->dobj.namespace)
    2048             :         /* default ACLs are considered part of the namespace */
    2049         188 :         dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
    2050             :     else
    2051         188 :         dinfo->dobj.dump = dopt->include_everything ?
    2052         188 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2053         376 : }
    2054             : 
    2055             : /*
    2056             :  * selectDumpableCast: policy-setting subroutine
    2057             :  *      Mark a cast as to be dumped or not
    2058             :  *
    2059             :  * Casts do not belong to any particular namespace (since they haven't got
    2060             :  * names), nor do they have identifiable owners.  To distinguish user-defined
    2061             :  * casts from built-in ones, we must resort to checking whether the cast's
    2062             :  * OID is in the range reserved for initdb.
    2063             :  */
    2064             : static void
    2065       71538 : selectDumpableCast(CastInfo *cast, Archive *fout)
    2066             : {
    2067       71538 :     if (checkExtensionMembership(&cast->dobj, fout))
    2068           0 :         return;                 /* extension membership overrides all else */
    2069             : 
    2070             :     /*
    2071             :      * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
    2072             :      * support ACLs currently.
    2073             :      */
    2074       71538 :     if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2075       71360 :         cast->dobj.dump = DUMP_COMPONENT_NONE;
    2076             :     else
    2077         178 :         cast->dobj.dump = fout->dopt->include_everything ?
    2078         178 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2079             : }
    2080             : 
    2081             : /*
    2082             :  * selectDumpableProcLang: policy-setting subroutine
    2083             :  *      Mark a procedural language as to be dumped or not
    2084             :  *
    2085             :  * Procedural languages do not belong to any particular namespace.  To
    2086             :  * identify built-in languages, we must resort to checking whether the
    2087             :  * language's OID is in the range reserved for initdb.
    2088             :  */
    2089             : static void
    2090         414 : selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
    2091             : {
    2092         414 :     if (checkExtensionMembership(&plang->dobj, fout))
    2093         320 :         return;                 /* extension membership overrides all else */
    2094             : 
    2095             :     /*
    2096             :      * Only include procedural languages when we are dumping everything.
    2097             :      *
    2098             :      * For from-initdb procedural languages, only include ACLs, as we do for
    2099             :      * the pg_catalog namespace.  We need this because procedural languages do
    2100             :      * not live in any namespace.
    2101             :      */
    2102          94 :     if (!fout->dopt->include_everything)
    2103          16 :         plang->dobj.dump = DUMP_COMPONENT_NONE;
    2104             :     else
    2105             :     {
    2106          78 :         if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2107           0 :             plang->dobj.dump = fout->remoteVersion < 90600 ?
    2108           0 :                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
    2109             :         else
    2110          78 :             plang->dobj.dump = DUMP_COMPONENT_ALL;
    2111             :     }
    2112             : }
    2113             : 
    2114             : /*
    2115             :  * selectDumpableAccessMethod: policy-setting subroutine
    2116             :  *      Mark an access method as to be dumped or not
    2117             :  *
    2118             :  * Access methods do not belong to any particular namespace.  To identify
    2119             :  * built-in access methods, we must resort to checking whether the
    2120             :  * method's OID is in the range reserved for initdb.
    2121             :  */
    2122             : static void
    2123        2492 : selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
    2124             : {
    2125        2492 :     if (checkExtensionMembership(&method->dobj, fout))
    2126          50 :         return;                 /* extension membership overrides all else */
    2127             : 
    2128             :     /*
    2129             :      * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
    2130             :      * they do not support ACLs currently.
    2131             :      */
    2132        2442 :     if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2133        2240 :         method->dobj.dump = DUMP_COMPONENT_NONE;
    2134             :     else
    2135         202 :         method->dobj.dump = fout->dopt->include_everything ?
    2136         202 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2137             : }
    2138             : 
    2139             : /*
    2140             :  * selectDumpableExtension: policy-setting subroutine
    2141             :  *      Mark an extension as to be dumped or not
    2142             :  *
    2143             :  * Built-in extensions should be skipped except for checking ACLs, since we
    2144             :  * assume those will already be installed in the target database.  We identify
    2145             :  * such extensions by their having OIDs in the range reserved for initdb.
    2146             :  * We dump all user-added extensions by default.  No extensions are dumped
    2147             :  * if include_everything is false (i.e., a --schema or --table switch was
    2148             :  * given), except if --extension specifies a list of extensions to dump.
    2149             :  */
    2150             : static void
    2151         372 : selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
    2152             : {
    2153             :     /*
    2154             :      * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
    2155             :      * change permissions on their member objects, if they wish to, and have
    2156             :      * those changes preserved.
    2157             :      */
    2158         372 :     if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
    2159         322 :         extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
    2160             :     else
    2161             :     {
    2162             :         /* check if there is a list of extensions to dump */
    2163          50 :         if (extension_include_oids.head != NULL)
    2164           8 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2165           8 :                 simple_oid_list_member(&extension_include_oids,
    2166             :                                        extinfo->dobj.catId.oid) ?
    2167           8 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2168             :         else
    2169          42 :             extinfo->dobj.dump = extinfo->dobj.dump_contains =
    2170          42 :                 dopt->include_everything ?
    2171          42 :                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2172             : 
    2173             :         /* check that the extension is not explicitly excluded */
    2174          92 :         if (extinfo->dobj.dump &&
    2175          42 :             simple_oid_list_member(&extension_exclude_oids,
    2176             :                                    extinfo->dobj.catId.oid))
    2177           4 :             extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
    2178             :     }
    2179         372 : }
    2180             : 
    2181             : /*
    2182             :  * selectDumpablePublicationObject: policy-setting subroutine
    2183             :  *      Mark a publication object as to be dumped or not
    2184             :  *
    2185             :  * A publication can have schemas and tables which have schemas, but those are
    2186             :  * ignored in decision making, because publications are only dumped when we are
    2187             :  * dumping everything.
    2188             :  */
    2189             : static void
    2190         846 : selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
    2191             : {
    2192         846 :     if (checkExtensionMembership(dobj, fout))
    2193           0 :         return;                 /* extension membership overrides all else */
    2194             : 
    2195         846 :     dobj->dump = fout->dopt->include_everything ?
    2196         846 :         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2197             : }
    2198             : 
    2199             : /*
    2200             :  * selectDumpableStatisticsObject: policy-setting subroutine
    2201             :  *      Mark an extended statistics object as to be dumped or not
    2202             :  *
    2203             :  * We dump an extended statistics object if the schema it's in and the table
    2204             :  * it's for are being dumped.  (This'll need more thought if statistics
    2205             :  * objects ever support cross-table stats.)
    2206             :  */
    2207             : static void
    2208         338 : selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
    2209             : {
    2210         338 :     if (checkExtensionMembership(&sobj->dobj, fout))
    2211           0 :         return;                 /* extension membership overrides all else */
    2212             : 
    2213         338 :     sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
    2214         338 :     if (sobj->stattable == NULL ||
    2215         338 :         !(sobj->stattable->dobj.dump & DUMP_COMPONENT_DEFINITION))
    2216          56 :         sobj->dobj.dump = DUMP_COMPONENT_NONE;
    2217             : }
    2218             : 
    2219             : /*
    2220             :  * selectDumpableObject: policy-setting subroutine
    2221             :  *      Mark a generic dumpable object as to be dumped or not
    2222             :  *
    2223             :  * Use this only for object types without a special-case routine above.
    2224             :  */
    2225             : static void
    2226      687616 : selectDumpableObject(DumpableObject *dobj, Archive *fout)
    2227             : {
    2228      687616 :     if (checkExtensionMembership(dobj, fout))
    2229         246 :         return;                 /* extension membership overrides all else */
    2230             : 
    2231             :     /*
    2232             :      * Default policy is to dump if parent namespace is dumpable, or for
    2233             :      * non-namespace-associated items, dump if we're dumping "everything".
    2234             :      */
    2235      687370 :     if (dobj->namespace)
    2236      686104 :         dobj->dump = dobj->namespace->dobj.dump_contains;
    2237             :     else
    2238        1266 :         dobj->dump = fout->dopt->include_everything ?
    2239        1266 :             DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
    2240             : }
    2241             : 
    2242             : /*
    2243             :  *  Dump a table's contents for loading using the COPY command
    2244             :  *  - this routine is called by the Archiver when it wants the table
    2245             :  *    to be dumped.
    2246             :  */
    2247             : static int
    2248        7554 : dumpTableData_copy(Archive *fout, const void *dcontext)
    2249             : {
    2250        7554 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2251        7554 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2252        7554 :     const char *classname = tbinfo->dobj.name;
    2253        7554 :     PQExpBuffer q = createPQExpBuffer();
    2254             : 
    2255             :     /*
    2256             :      * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
    2257             :      * which uses it already.
    2258             :      */
    2259        7554 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2260        7554 :     PGconn     *conn = GetConnection(fout);
    2261             :     PGresult   *res;
    2262             :     int         ret;
    2263             :     char       *copybuf;
    2264             :     const char *column_list;
    2265             : 
    2266        7554 :     pg_log_info("dumping contents of table \"%s.%s\"",
    2267             :                 tbinfo->dobj.namespace->dobj.name, classname);
    2268             : 
    2269             :     /*
    2270             :      * Specify the column list explicitly so that we have no possibility of
    2271             :      * retrieving data in the wrong column order.  (The default column
    2272             :      * ordering of COPY will not be what we want in certain corner cases
    2273             :      * involving ADD COLUMN and inheritance.)
    2274             :      */
    2275        7554 :     column_list = fmtCopyColumnList(tbinfo, clistBuf);
    2276             : 
    2277             :     /*
    2278             :      * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
    2279             :      * a filter condition was specified.  For other cases a simple COPY
    2280             :      * suffices.
    2281             :      */
    2282        7554 :     if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2283             :     {
    2284             :         /* Temporary allows to access to foreign tables to dump data */
    2285           2 :         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2286           2 :             set_restrict_relation_kind(fout, "view");
    2287             : 
    2288           2 :         appendPQExpBufferStr(q, "COPY (SELECT ");
    2289             :         /* klugery to get rid of parens in column list */
    2290           2 :         if (strlen(column_list) > 2)
    2291             :         {
    2292           2 :             appendPQExpBufferStr(q, column_list + 1);
    2293           2 :             q->data[q->len - 1] = ' ';
    2294             :         }
    2295             :         else
    2296           0 :             appendPQExpBufferStr(q, "* ");
    2297             : 
    2298           4 :         appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
    2299           2 :                           fmtQualifiedDumpable(tbinfo),
    2300           2 :                           tdinfo->filtercond ? tdinfo->filtercond : "");
    2301             :     }
    2302             :     else
    2303             :     {
    2304        7552 :         appendPQExpBuffer(q, "COPY %s %s TO stdout;",
    2305        7552 :                           fmtQualifiedDumpable(tbinfo),
    2306             :                           column_list);
    2307             :     }
    2308        7554 :     res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
    2309        7552 :     PQclear(res);
    2310        7552 :     destroyPQExpBuffer(clistBuf);
    2311             : 
    2312             :     for (;;)
    2313             :     {
    2314     3614714 :         ret = PQgetCopyData(conn, &copybuf, 0);
    2315             : 
    2316     3614714 :         if (ret < 0)
    2317        7552 :             break;              /* done or error */
    2318             : 
    2319     3607162 :         if (copybuf)
    2320             :         {
    2321     3607162 :             WriteData(fout, copybuf, ret);
    2322     3607162 :             PQfreemem(copybuf);
    2323             :         }
    2324             : 
    2325             :         /* ----------
    2326             :          * THROTTLE:
    2327             :          *
    2328             :          * There was considerable discussion in late July, 2000 regarding
    2329             :          * slowing down pg_dump when backing up large tables. Users with both
    2330             :          * slow & fast (multi-processor) machines experienced performance
    2331             :          * degradation when doing a backup.
    2332             :          *
    2333             :          * Initial attempts based on sleeping for a number of ms for each ms
    2334             :          * of work were deemed too complex, then a simple 'sleep in each loop'
    2335             :          * implementation was suggested. The latter failed because the loop
    2336             :          * was too tight. Finally, the following was implemented:
    2337             :          *
    2338             :          * If throttle is non-zero, then
    2339             :          *      See how long since the last sleep.
    2340             :          *      Work out how long to sleep (based on ratio).
    2341             :          *      If sleep is more than 100ms, then
    2342             :          *          sleep
    2343             :          *          reset timer
    2344             :          *      EndIf
    2345             :          * EndIf
    2346             :          *
    2347             :          * where the throttle value was the number of ms to sleep per ms of
    2348             :          * work. The calculation was done in each loop.
    2349             :          *
    2350             :          * Most of the hard work is done in the backend, and this solution
    2351             :          * still did not work particularly well: on slow machines, the ratio
    2352             :          * was 50:1, and on medium paced machines, 1:1, and on fast
    2353             :          * multi-processor machines, it had little or no effect, for reasons
    2354             :          * that were unclear.
    2355             :          *
    2356             :          * Further discussion ensued, and the proposal was dropped.
    2357             :          *
    2358             :          * For those people who want this feature, it can be implemented using
    2359             :          * gettimeofday in each loop, calculating the time since last sleep,
    2360             :          * multiplying that by the sleep ratio, then if the result is more
    2361             :          * than a preset 'minimum sleep time' (say 100ms), call the 'select'
    2362             :          * function to sleep for a subsecond period ie.
    2363             :          *
    2364             :          * select(0, NULL, NULL, NULL, &tvi);
    2365             :          *
    2366             :          * This will return after the interval specified in the structure tvi.
    2367             :          * Finally, call gettimeofday again to save the 'last sleep time'.
    2368             :          * ----------
    2369             :          */
    2370             :     }
    2371        7552 :     archprintf(fout, "\\.\n\n\n");
    2372             : 
    2373        7552 :     if (ret == -2)
    2374             :     {
    2375             :         /* copy data transfer failed */
    2376           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
    2377           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2378           0 :         pg_log_error_detail("Command was: %s", q->data);
    2379           0 :         exit_nicely(1);
    2380             :     }
    2381             : 
    2382             :     /* Check command status and return to normal libpq state */
    2383        7552 :     res = PQgetResult(conn);
    2384        7552 :     if (PQresultStatus(res) != PGRES_COMMAND_OK)
    2385             :     {
    2386           0 :         pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
    2387           0 :         pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
    2388           0 :         pg_log_error_detail("Command was: %s", q->data);
    2389           0 :         exit_nicely(1);
    2390             :     }
    2391        7552 :     PQclear(res);
    2392             : 
    2393             :     /* Do this to ensure we've pumped libpq back to idle state */
    2394        7552 :     if (PQgetResult(conn) != NULL)
    2395           0 :         pg_log_warning("unexpected extra results during COPY of table \"%s\"",
    2396             :                        classname);
    2397             : 
    2398        7552 :     destroyPQExpBuffer(q);
    2399             : 
    2400             :     /* Revert back the setting */
    2401        7552 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2402           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2403             : 
    2404        7552 :     return 1;
    2405             : }
    2406             : 
    2407             : /*
    2408             :  * Dump table data using INSERT commands.
    2409             :  *
    2410             :  * Caution: when we restore from an archive file direct to database, the
    2411             :  * INSERT commands emitted by this function have to be parsed by
    2412             :  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
    2413             :  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
    2414             :  */
    2415             : static int
    2416         142 : dumpTableData_insert(Archive *fout, const void *dcontext)
    2417             : {
    2418         142 :     TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
    2419         142 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2420         142 :     DumpOptions *dopt = fout->dopt;
    2421         142 :     PQExpBuffer q = createPQExpBuffer();
    2422         142 :     PQExpBuffer insertStmt = NULL;
    2423             :     char       *attgenerated;
    2424             :     PGresult   *res;
    2425             :     int         nfields,
    2426             :                 i;
    2427         142 :     int         rows_per_statement = dopt->dump_inserts;
    2428         142 :     int         rows_this_statement = 0;
    2429             : 
    2430             :     /* Temporary allows to access to foreign tables to dump data */
    2431         142 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2432           0 :         set_restrict_relation_kind(fout, "view");
    2433             : 
    2434             :     /*
    2435             :      * If we're going to emit INSERTs with column names, the most efficient
    2436             :      * way to deal with generated columns is to exclude them entirely.  For
    2437             :      * INSERTs without column names, we have to emit DEFAULT rather than the
    2438             :      * actual column value --- but we can save a few cycles by fetching nulls
    2439             :      * rather than the uninteresting-to-us value.
    2440             :      */
    2441         142 :     attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
    2442         142 :     appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
    2443         142 :     nfields = 0;
    2444         466 :     for (i = 0; i < tbinfo->numatts; i++)
    2445             :     {
    2446         324 :         if (tbinfo->attisdropped[i])
    2447           4 :             continue;
    2448         320 :         if (tbinfo->attgenerated[i] && dopt->column_inserts)
    2449          16 :             continue;
    2450         304 :         if (nfields > 0)
    2451         176 :             appendPQExpBufferStr(q, ", ");
    2452         304 :         if (tbinfo->attgenerated[i])
    2453          16 :             appendPQExpBufferStr(q, "NULL");
    2454             :         else
    2455         288 :             appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
    2456         304 :         attgenerated[nfields] = tbinfo->attgenerated[i];
    2457         304 :         nfields++;
    2458             :     }
    2459             :     /* Servers before 9.4 will complain about zero-column SELECT */
    2460         142 :     if (nfields == 0)
    2461          14 :         appendPQExpBufferStr(q, "NULL");
    2462         142 :     appendPQExpBuffer(q, " FROM ONLY %s",
    2463         142 :                       fmtQualifiedDumpable(tbinfo));
    2464         142 :     if (tdinfo->filtercond)
    2465           0 :         appendPQExpBuffer(q, " %s", tdinfo->filtercond);
    2466             : 
    2467         142 :     ExecuteSqlStatement(fout, q->data);
    2468             : 
    2469             :     while (1)
    2470             :     {
    2471         246 :         res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
    2472             :                               PGRES_TUPLES_OK);
    2473             : 
    2474             :         /* cross-check field count, allowing for dummy NULL if any */
    2475         246 :         if (nfields != PQnfields(res) &&
    2476          20 :             !(nfields == 0 && PQnfields(res) == 1))
    2477           0 :             pg_fatal("wrong number of fields retrieved from table \"%s\"",
    2478             :                      tbinfo->dobj.name);
    2479             : 
    2480             :         /*
    2481             :          * First time through, we build as much of the INSERT statement as
    2482             :          * possible in "insertStmt", which we can then just print for each
    2483             :          * statement. If the table happens to have zero dumpable columns then
    2484             :          * this will be a complete statement, otherwise it will end in
    2485             :          * "VALUES" and be ready to have the row's column values printed.
    2486             :          */
    2487         246 :         if (insertStmt == NULL)
    2488             :         {
    2489             :             TableInfo  *targettab;
    2490             : 
    2491         142 :             insertStmt = createPQExpBuffer();
    2492             : 
    2493             :             /*
    2494             :              * When load-via-partition-root is set or forced, get the root
    2495             :              * table name for the partition table, so that we can reload data
    2496             :              * through the root table.
    2497             :              */
    2498         142 :             if (tbinfo->ispartition &&
    2499          80 :                 (dopt->load_via_partition_root ||
    2500          40 :                  forcePartitionRootLoad(tbinfo)))
    2501           6 :                 targettab = getRootTableInfo(tbinfo);
    2502             :             else
    2503         136 :                 targettab = tbinfo;
    2504             : 
    2505         142 :             appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
    2506         142 :                               fmtQualifiedDumpable(targettab));
    2507             : 
    2508             :             /* corner case for zero-column table */
    2509         142 :             if (nfields == 0)
    2510             :             {
    2511          14 :                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
    2512             :             }
    2513             :             else
    2514             :             {
    2515             :                 /* append the list of column names if required */
    2516         128 :                 if (dopt->column_inserts)
    2517             :                 {
    2518          56 :                     appendPQExpBufferChar(insertStmt, '(');
    2519         182 :                     for (int field = 0; field < nfields; field++)
    2520             :                     {
    2521         126 :                         if (field > 0)
    2522          70 :                             appendPQExpBufferStr(insertStmt, ", ");
    2523         126 :                         appendPQExpBufferStr(insertStmt,
    2524         126 :                                              fmtId(PQfname(res, field)));
    2525             :                     }
    2526          56 :                     appendPQExpBufferStr(insertStmt, ") ");
    2527             :                 }
    2528             : 
    2529         128 :                 if (tbinfo->needs_override)
    2530           4 :                     appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
    2531             : 
    2532         128 :                 appendPQExpBufferStr(insertStmt, "VALUES");
    2533             :             }
    2534             :         }
    2535             : 
    2536        6788 :         for (int tuple = 0; tuple < PQntuples(res); tuple++)
    2537             :         {
    2538             :             /* Write the INSERT if not in the middle of a multi-row INSERT. */
    2539        6542 :             if (rows_this_statement == 0)
    2540        6530 :                 archputs(insertStmt->data, fout);
    2541             : 
    2542             :             /*
    2543             :              * If it is zero-column table then we've already written the
    2544             :              * complete statement, which will mean we've disobeyed
    2545             :              * --rows-per-insert when it's set greater than 1.  We do support
    2546             :              * a way to make this multi-row with: SELECT UNION ALL SELECT
    2547             :              * UNION ALL ... but that's non-standard so we should avoid it
    2548             :              * given that using INSERTs is mostly only ever needed for
    2549             :              * cross-database exports.
    2550             :              */
    2551        6542 :             if (nfields == 0)
    2552          12 :                 continue;
    2553             : 
    2554             :             /* Emit a row heading */
    2555        6530 :             if (rows_per_statement == 1)
    2556        6512 :                 archputs(" (", fout);
    2557          18 :             else if (rows_this_statement > 0)
    2558          12 :                 archputs(",\n\t(", fout);
    2559             :             else
    2560           6 :                 archputs("\n\t(", fout);
    2561             : 
    2562       19698 :             for (int field = 0; field < nfields; field++)
    2563             :             {
    2564       13168 :                 if (field > 0)
    2565        6638 :                     archputs(", ", fout);
    2566       13168 :                 if (attgenerated[field])
    2567             :                 {
    2568           4 :                     archputs("DEFAULT", fout);
    2569           4 :                     continue;
    2570             :                 }
    2571       13164 :                 if (PQgetisnull(res, tuple, field))
    2572             :                 {
    2573         166 :                     archputs("NULL", fout);
    2574         166 :                     continue;
    2575             :                 }
    2576             : 
    2577             :                 /* XXX This code is partially duplicated in ruleutils.c */
    2578       12998 :                 switch (PQftype(res, field))
    2579             :                 {
    2580        8938 :                     case INT2OID:
    2581             :                     case INT4OID:
    2582             :                     case INT8OID:
    2583             :                     case OIDOID:
    2584             :                     case FLOAT4OID:
    2585             :                     case FLOAT8OID:
    2586             :                     case NUMERICOID:
    2587             :                         {
    2588             :                             /*
    2589             :                              * These types are printed without quotes unless
    2590             :                              * they contain values that aren't accepted by the
    2591             :                              * scanner unquoted (e.g., 'NaN').  Note that
    2592             :                              * strtod() and friends might accept NaN, so we
    2593             :                              * can't use that to test.
    2594             :                              *
    2595             :                              * In reality we only need to defend against
    2596             :                              * infinity and NaN, so we need not get too crazy
    2597             :                              * about pattern matching here.
    2598             :                              */
    2599        8938 :                             const char *s = PQgetvalue(res, tuple, field);
    2600             : 
    2601        8938 :                             if (strspn(s, "0123456789 +-eE.") == strlen(s))
    2602        8934 :                                 archputs(s, fout);
    2603             :                             else
    2604           4 :                                 archprintf(fout, "'%s'", s);
    2605             :                         }
    2606        8938 :                         break;
    2607             : 
    2608           4 :                     case BITOID:
    2609             :                     case VARBITOID:
    2610           4 :                         archprintf(fout, "B'%s'",
    2611             :                                    PQgetvalue(res, tuple, field));
    2612           4 :                         break;
    2613             : 
    2614           8 :                     case BOOLOID:
    2615           8 :                         if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
    2616           4 :                             archputs("true", fout);
    2617             :                         else
    2618           4 :                             archputs("false", fout);
    2619           8 :                         break;
    2620             : 
    2621        4048 :                     default:
    2622             :                         /* All other types are printed as string literals. */
    2623        4048 :                         resetPQExpBuffer(q);
    2624        4048 :                         appendStringLiteralAH(q,
    2625             :                                               PQgetvalue(res, tuple, field),
    2626             :                                               fout);
    2627        4048 :                         archputs(q->data, fout);
    2628        4048 :                         break;
    2629             :                 }
    2630             :             }
    2631             : 
    2632             :             /* Terminate the row ... */
    2633        6530 :             archputs(")", fout);
    2634             : 
    2635             :             /* ... and the statement, if the target no. of rows is reached */
    2636        6530 :             if (++rows_this_statement >= rows_per_statement)
    2637             :             {
    2638        6516 :                 if (dopt->do_nothing)
    2639           0 :                     archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2640             :                 else
    2641        6516 :                     archputs(";\n", fout);
    2642             :                 /* Reset the row counter */
    2643        6516 :                 rows_this_statement = 0;
    2644             :             }
    2645             :         }
    2646             : 
    2647         246 :         if (PQntuples(res) <= 0)
    2648             :         {
    2649         142 :             PQclear(res);
    2650         142 :             break;
    2651             :         }
    2652         104 :         PQclear(res);
    2653             :     }
    2654             : 
    2655             :     /* Terminate any statements that didn't make the row count. */
    2656         142 :     if (rows_this_statement > 0)
    2657             :     {
    2658           2 :         if (dopt->do_nothing)
    2659           0 :             archputs(" ON CONFLICT DO NOTHING;\n", fout);
    2660             :         else
    2661           2 :             archputs(";\n", fout);
    2662             :     }
    2663             : 
    2664         142 :     archputs("\n\n", fout);
    2665             : 
    2666         142 :     ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
    2667             : 
    2668         142 :     destroyPQExpBuffer(q);
    2669         142 :     if (insertStmt != NULL)
    2670         142 :         destroyPQExpBuffer(insertStmt);
    2671         142 :     free(attgenerated);
    2672             : 
    2673             :     /* Revert back the setting */
    2674         142 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
    2675           0 :         set_restrict_relation_kind(fout, "view, foreign-table");
    2676             : 
    2677         142 :     return 1;
    2678             : }
    2679             : 
    2680             : /*
    2681             :  * getRootTableInfo:
    2682             :  *     get the root TableInfo for the given partition table.
    2683             :  */
    2684             : static TableInfo *
    2685          18 : getRootTableInfo(const TableInfo *tbinfo)
    2686             : {
    2687             :     TableInfo  *parentTbinfo;
    2688             : 
    2689             :     Assert(tbinfo->ispartition);
    2690             :     Assert(tbinfo->numParents == 1);
    2691             : 
    2692          18 :     parentTbinfo = tbinfo->parents[0];
    2693          18 :     while (parentTbinfo->ispartition)
    2694             :     {
    2695             :         Assert(parentTbinfo->numParents == 1);
    2696           0 :         parentTbinfo = parentTbinfo->parents[0];
    2697             :     }
    2698             : 
    2699          18 :     return parentTbinfo;
    2700             : }
    2701             : 
    2702             : /*
    2703             :  * forcePartitionRootLoad
    2704             :  *     Check if we must force load_via_partition_root for this partition.
    2705             :  *
    2706             :  * This is required if any level of ancestral partitioned table has an
    2707             :  * unsafe partitioning scheme.
    2708             :  */
    2709             : static bool
    2710        1936 : forcePartitionRootLoad(const TableInfo *tbinfo)
    2711             : {
    2712             :     TableInfo  *parentTbinfo;
    2713             : 
    2714             :     Assert(tbinfo->ispartition);
    2715             :     Assert(tbinfo->numParents == 1);
    2716             : 
    2717        1936 :     parentTbinfo = tbinfo->parents[0];
    2718        1936 :     if (parentTbinfo->unsafe_partitions)
    2719          18 :         return true;
    2720        2350 :     while (parentTbinfo->ispartition)
    2721             :     {
    2722             :         Assert(parentTbinfo->numParents == 1);
    2723         432 :         parentTbinfo = parentTbinfo->parents[0];
    2724         432 :         if (parentTbinfo->unsafe_partitions)
    2725           0 :             return true;
    2726             :     }
    2727             : 
    2728        1918 :     return false;
    2729             : }
    2730             : 
    2731             : /*
    2732             :  * dumpTableData -
    2733             :  *    dump the contents of a single table
    2734             :  *
    2735             :  * Actually, this just makes an ArchiveEntry for the table contents.
    2736             :  */
    2737             : static void
    2738        7836 : dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
    2739             : {
    2740        7836 :     DumpOptions *dopt = fout->dopt;
    2741        7836 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2742        7836 :     PQExpBuffer copyBuf = createPQExpBuffer();
    2743        7836 :     PQExpBuffer clistBuf = createPQExpBuffer();
    2744             :     DataDumperPtr dumpFn;
    2745        7836 :     char       *tdDefn = NULL;
    2746             :     char       *copyStmt;
    2747             :     const char *copyFrom;
    2748             : 
    2749             :     /* We had better have loaded per-column details about this table */
    2750             :     Assert(tbinfo->interesting);
    2751             : 
    2752             :     /*
    2753             :      * When load-via-partition-root is set or forced, get the root table name
    2754             :      * for the partition table, so that we can reload data through the root
    2755             :      * table.  Then construct a comment to be inserted into the TOC entry's
    2756             :      * defn field, so that such cases can be identified reliably.
    2757             :      */
    2758        7836 :     if (tbinfo->ispartition &&
    2759        3792 :         (dopt->load_via_partition_root ||
    2760        1896 :          forcePartitionRootLoad(tbinfo)))
    2761          12 :     {
    2762             :         TableInfo  *parentTbinfo;
    2763             : 
    2764          12 :         parentTbinfo = getRootTableInfo(tbinfo);
    2765          12 :         copyFrom = fmtQualifiedDumpable(parentTbinfo);
    2766          12 :         printfPQExpBuffer(copyBuf, "-- load via partition root %s",
    2767             :                           copyFrom);
    2768          12 :         tdDefn = pg_strdup(copyBuf->data);
    2769             :     }
    2770             :     else
    2771        7824 :         copyFrom = fmtQualifiedDumpable(tbinfo);
    2772             : 
    2773        7836 :     if (dopt->dump_inserts == 0)
    2774             :     {
    2775             :         /* Dump/restore using COPY */
    2776        7694 :         dumpFn = dumpTableData_copy;
    2777             :         /* must use 2 steps here 'cause fmtId is nonreentrant */
    2778        7694 :         printfPQExpBuffer(copyBuf, "COPY %s ",
    2779             :                           copyFrom);
    2780        7694 :         appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
    2781             :                           fmtCopyColumnList(tbinfo, clistBuf));
    2782        7694 :         copyStmt = copyBuf->data;
    2783             :     }
    2784             :     else
    2785             :     {
    2786             :         /* Restore using INSERT */
    2787         142 :         dumpFn = dumpTableData_insert;
    2788         142 :         copyStmt = NULL;
    2789             :     }
    2790             : 
    2791             :     /*
    2792             :      * Note: although the TableDataInfo is a full DumpableObject, we treat its
    2793             :      * dependency on its table as "special" and pass it to ArchiveEntry now.
    2794             :      * See comments for BuildArchiveDependencies.
    2795             :      */
    2796        7836 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2797             :     {
    2798             :         TocEntry   *te;
    2799             : 
    2800        7836 :         te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
    2801        7836 :                           ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2802             :                                        .namespace = tbinfo->dobj.namespace->dobj.name,
    2803             :                                        .owner = tbinfo->rolname,
    2804             :                                        .description = "TABLE DATA",
    2805             :                                        .section = SECTION_DATA,
    2806             :                                        .createStmt = tdDefn,
    2807             :                                        .copyStmt = copyStmt,
    2808             :                                        .deps = &(tbinfo->dobj.dumpId),
    2809             :                                        .nDeps = 1,
    2810             :                                        .dumpFn = dumpFn,
    2811             :                                        .dumpArg = tdinfo));
    2812             : 
    2813             :         /*
    2814             :          * Set the TocEntry's dataLength in case we are doing a parallel dump
    2815             :          * and want to order dump jobs by table size.  We choose to measure
    2816             :          * dataLength in table pages (including TOAST pages) during dump, so
    2817             :          * no scaling is needed.
    2818             :          *
    2819             :          * However, relpages is declared as "integer" in pg_class, and hence
    2820             :          * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
    2821             :          * Cast so that we get the right interpretation of table sizes
    2822             :          * exceeding INT_MAX pages.
    2823             :          */
    2824        7836 :         te->dataLength = (BlockNumber) tbinfo->relpages;
    2825        7836 :         te->dataLength += (BlockNumber) tbinfo->toastpages;
    2826             : 
    2827             :         /*
    2828             :          * If pgoff_t is only 32 bits wide, the above refinement is useless,
    2829             :          * and instead we'd better worry about integer overflow.  Clamp to
    2830             :          * INT_MAX if the correct result exceeds that.
    2831             :          */
    2832             :         if (sizeof(te->dataLength) == 4 &&
    2833             :             (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
    2834             :              te->dataLength < 0))
    2835             :             te->dataLength = INT_MAX;
    2836             :     }
    2837             : 
    2838        7836 :     destroyPQExpBuffer(copyBuf);
    2839        7836 :     destroyPQExpBuffer(clistBuf);
    2840        7836 : }
    2841             : 
    2842             : /*
    2843             :  * refreshMatViewData -
    2844             :  *    load or refresh the contents of a single materialized view
    2845             :  *
    2846             :  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
    2847             :  * statement.
    2848             :  */
    2849             : static void
    2850         784 : refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
    2851             : {
    2852         784 :     TableInfo  *tbinfo = tdinfo->tdtable;
    2853             :     PQExpBuffer q;
    2854             : 
    2855             :     /* If the materialized view is not flagged as populated, skip this. */
    2856         784 :     if (!tbinfo->relispopulated)
    2857         144 :         return;
    2858             : 
    2859         640 :     q = createPQExpBuffer();
    2860             : 
    2861         640 :     appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
    2862         640 :                       fmtQualifiedDumpable(tbinfo));
    2863             : 
    2864         640 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
    2865         640 :         ArchiveEntry(fout,
    2866             :                      tdinfo->dobj.catId, /* catalog ID */
    2867             :                      tdinfo->dobj.dumpId,    /* dump ID */
    2868         640 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
    2869             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    2870             :                                   .owner = tbinfo->rolname,
    2871             :                                   .description = "MATERIALIZED VIEW DATA",
    2872             :                                   .section = SECTION_POST_DATA,
    2873             :                                   .createStmt = q->data,
    2874             :                                   .deps = tdinfo->dobj.dependencies,
    2875             :                                   .nDeps = tdinfo->dobj.nDeps));
    2876             : 
    2877         640 :     destroyPQExpBuffer(q);
    2878             : }
    2879             : 
    2880             : /*
    2881             :  * getTableData -
    2882             :  *    set up dumpable objects representing the contents of tables
    2883             :  */
    2884             : static void
    2885         312 : getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
    2886             : {
    2887             :     int         i;
    2888             : 
    2889       83040 :     for (i = 0; i < numTables; i++)
    2890             :     {
    2891       82728 :         if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
    2892        1742 :             (!relkind || tblinfo[i].relkind == relkind))
    2893       11300 :             makeTableDataInfo(dopt, &(tblinfo[i]));
    2894             :     }
    2895         312 : }
    2896             : 
    2897             : /*
    2898             :  * Make a dumpable object for the data of this specific table
    2899             :  *
    2900             :  * Note: we make a TableDataInfo if and only if we are going to dump the
    2901             :  * table data; the "dump" field in such objects isn't very interesting.
    2902             :  */
    2903             : static void
    2904       11378 : makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
    2905             : {
    2906             :     TableDataInfo *tdinfo;
    2907             : 
    2908             :     /*
    2909             :      * Nothing to do if we already decided to dump the table.  This will
    2910             :      * happen for "config" tables.
    2911             :      */
    2912       11378 :     if (tbinfo->dataObj != NULL)
    2913           2 :         return;
    2914             : 
    2915             :     /* Skip VIEWs (no data to dump) */
    2916       11376 :     if (tbinfo->relkind == RELKIND_VIEW)
    2917         940 :         return;
    2918             :     /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
    2919       10436 :     if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
    2920          80 :         (foreign_servers_include_oids.head == NULL ||
    2921           8 :          !simple_oid_list_member(&foreign_servers_include_oids,
    2922             :                                  tbinfo->foreign_server)))
    2923          78 :         return;
    2924             :     /* Skip partitioned tables (data in partitions) */
    2925       10358 :     if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
    2926         896 :         return;
    2927             : 
    2928             :     /* Don't dump data in unlogged tables, if so requested */
    2929        9462 :     if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
    2930          82 :         dopt->no_unlogged_table_data)
    2931          36 :         return;
    2932             : 
    2933             :     /* Check that the data is not explicitly excluded */
    2934        9426 :     if (simple_oid_list_member(&tabledata_exclude_oids,
    2935             :                                tbinfo->dobj.catId.oid))
    2936          16 :         return;
    2937             : 
    2938             :     /* OK, let's dump it */
    2939        9410 :     tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
    2940             : 
    2941        9410 :     if (tbinfo->relkind == RELKIND_MATVIEW)
    2942         784 :         tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
    2943        8626 :     else if (tbinfo->relkind == RELKIND_SEQUENCE)
    2944         790 :         tdinfo->dobj.objType = DO_SEQUENCE_SET;
    2945             :     else
    2946        7836 :         tdinfo->dobj.objType = DO_TABLE_DATA;
    2947             : 
    2948             :     /*
    2949             :      * Note: use tableoid 0 so that this object won't be mistaken for
    2950             :      * something that pg_depend entries apply to.
    2951             :      */
    2952        9410 :     tdinfo->dobj.catId.tableoid = 0;
    2953        9410 :     tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    2954        9410 :     AssignDumpId(&tdinfo->dobj);
    2955        9410 :     tdinfo->dobj.name = tbinfo->dobj.name;
    2956        9410 :     tdinfo->dobj.namespace = tbinfo->dobj.namespace;
    2957        9410 :     tdinfo->tdtable = tbinfo;
    2958        9410 :     tdinfo->filtercond = NULL;   /* might get set later */
    2959        9410 :     addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
    2960             : 
    2961             :     /* A TableDataInfo contains data, of course */
    2962        9410 :     tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
    2963             : 
    2964        9410 :     tbinfo->dataObj = tdinfo;
    2965             : 
    2966             :     /* Make sure that we'll collect per-column info for this table. */
    2967        9410 :     tbinfo->interesting = true;
    2968             : }
    2969             : 
    2970             : /*
    2971             :  * The refresh for a materialized view must be dependent on the refresh for
    2972             :  * any materialized view that this one is dependent on.
    2973             :  *
    2974             :  * This must be called after all the objects are created, but before they are
    2975             :  * sorted.
    2976             :  */
    2977             : static void
    2978         280 : buildMatViewRefreshDependencies(Archive *fout)
    2979             : {
    2980             :     PQExpBuffer query;
    2981             :     PGresult   *res;
    2982             :     int         ntups,
    2983             :                 i;
    2984             :     int         i_classid,
    2985             :                 i_objid,
    2986             :                 i_refobjid;
    2987             : 
    2988             :     /* No Mat Views before 9.3. */
    2989         280 :     if (fout->remoteVersion < 90300)
    2990           0 :         return;
    2991             : 
    2992         280 :     query = createPQExpBuffer();
    2993             : 
    2994         280 :     appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
    2995             :                          "( "
    2996             :                          "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
    2997             :                          "FROM pg_depend d1 "
    2998             :                          "JOIN pg_class c1 ON c1.oid = d1.objid "
    2999             :                          "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
    3000             :                          " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
    3001             :                          "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
    3002             :                          "AND d2.objid = r1.oid "
    3003             :                          "AND d2.refobjid <> d1.objid "
    3004             :                          "JOIN pg_class c2 ON c2.oid = d2.refobjid "
    3005             :                          "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3006             :                          CppAsString2(RELKIND_VIEW) ") "
    3007             :                          "WHERE d1.classid = 'pg_class'::regclass "
    3008             :                          "UNION "
    3009             :                          "SELECT w.objid, d3.refobjid, c3.relkind "
    3010             :                          "FROM w "
    3011             :                          "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
    3012             :                          "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
    3013             :                          "AND d3.objid = r3.oid "
    3014             :                          "AND d3.refobjid <> w.refobjid "
    3015             :                          "JOIN pg_class c3 ON c3.oid = d3.refobjid "
    3016             :                          "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
    3017             :                          CppAsString2(RELKIND_VIEW) ") "
    3018             :                          ") "
    3019             :                          "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
    3020             :                          "FROM w "
    3021             :                          "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
    3022             : 
    3023         280 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    3024             : 
    3025         280 :     ntups = PQntuples(res);
    3026             : 
    3027         280 :     i_classid = PQfnumber(res, "classid");
    3028         280 :     i_objid = PQfnumber(res, "objid");
    3029         280 :     i_refobjid = PQfnumber(res, "refobjid");
    3030             : 
    3031         832 :     for (i = 0; i < ntups; i++)
    3032             :     {
    3033             :         CatalogId   objId;
    3034             :         CatalogId   refobjId;
    3035             :         DumpableObject *dobj;
    3036             :         DumpableObject *refdobj;
    3037             :         TableInfo  *tbinfo;
    3038             :         TableInfo  *reftbinfo;
    3039             : 
    3040         552 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
    3041         552 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
    3042         552 :         refobjId.tableoid = objId.tableoid;
    3043         552 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
    3044             : 
    3045         552 :         dobj = findObjectByCatalogId(objId);
    3046         552 :         if (dobj == NULL)
    3047          96 :             continue;
    3048             : 
    3049             :         Assert(dobj->objType == DO_TABLE);
    3050         552 :         tbinfo = (TableInfo *) dobj;
    3051             :         Assert(tbinfo->relkind == RELKIND_MATVIEW);
    3052         552 :         dobj = (DumpableObject *) tbinfo->dataObj;
    3053         552 :         if (dobj == NULL)
    3054          96 :             continue;
    3055             :         Assert(dobj->objType == DO_REFRESH_MATVIEW);
    3056             : 
    3057         456 :         refdobj = findObjectByCatalogId(refobjId);
    3058         456 :         if (refdobj == NULL)
    3059           0 :             continue;
    3060             : 
    3061             :         Assert(refdobj->objType == DO_TABLE);
    3062         456 :         reftbinfo = (TableInfo *) refdobj;
    3063             :         Assert(reftbinfo->relkind == RELKIND_MATVIEW);
    3064         456 :         refdobj = (DumpableObject *) reftbinfo->dataObj;
    3065         456 :         if (refdobj == NULL)
    3066           0 :             continue;
    3067             :         Assert(refdobj->objType == DO_REFRESH_MATVIEW);
    3068             : 
    3069         456 :         addObjectDependency(dobj, refdobj->dumpId);
    3070             : 
    3071         456 :         if (!reftbinfo->relispopulated)
    3072          72 :             tbinfo->relispopulated = false;
    3073             :     }
    3074             : 
    3075         280 :     PQclear(res);
    3076             : 
    3077         280 :     destroyPQExpBuffer(query);
    3078             : }
    3079             : 
    3080             : /*
    3081             :  * getTableDataFKConstraints -
    3082             :  *    add dump-order dependencies reflecting foreign key constraints
    3083             :  *
    3084             :  * This code is executed only in a data-only dump --- in schema+data dumps
    3085             :  * we handle foreign key issues by not creating the FK constraints until
    3086             :  * after the data is loaded.  In a data-only dump, however, we want to
    3087             :  * order the table data objects in such a way that a table's referenced
    3088             :  * tables are restored first.  (In the presence of circular references or
    3089             :  * self-references this may be impossible; we'll detect and complain about
    3090             :  * that during the dependency sorting step.)
    3091             :  */
    3092             : static void
    3093          14 : getTableDataFKConstraints(void)
    3094             : {
    3095             :     DumpableObject **dobjs;
    3096             :     int         numObjs;
    3097             :     int         i;
    3098             : 
    3099             :     /* Search through all the dumpable objects for FK constraints */
    3100          14 :     getDumpableObjects(&dobjs, &numObjs);
    3101       50484 :     for (i = 0; i < numObjs; i++)
    3102             :     {
    3103       50470 :         if (dobjs[i]->objType == DO_FK_CONSTRAINT)
    3104             :         {
    3105          16 :             ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
    3106             :             TableInfo  *ftable;
    3107             : 
    3108             :             /* Not interesting unless both tables are to be dumped */
    3109          16 :             if (cinfo->contable == NULL ||
    3110          16 :                 cinfo->contable->dataObj == NULL)
    3111           8 :                 continue;
    3112           8 :             ftable = findTableByOid(cinfo->confrelid);
    3113           8 :             if (ftable == NULL ||
    3114           8 :                 ftable->dataObj == NULL)
    3115           0 :                 continue;
    3116             : 
    3117             :             /*
    3118             :              * Okay, make referencing table's TABLE_DATA object depend on the
    3119             :              * referenced table's TABLE_DATA object.
    3120             :              */
    3121           8 :             addObjectDependency(&cinfo->contable->dataObj->dobj,
    3122           8 :                                 ftable->dataObj->dobj.dumpId);
    3123             :         }
    3124             :     }
    3125          14 :     free(dobjs);
    3126          14 : }
    3127             : 
    3128             : 
    3129             : /*
    3130             :  * dumpDatabase:
    3131             :  *  dump the database definition
    3132             :  */
    3133             : static void
    3134         124 : dumpDatabase(Archive *fout)
    3135             : {
    3136         124 :     DumpOptions *dopt = fout->dopt;
    3137         124 :     PQExpBuffer dbQry = createPQExpBuffer();
    3138         124 :     PQExpBuffer delQry = createPQExpBuffer();
    3139         124 :     PQExpBuffer creaQry = createPQExpBuffer();
    3140         124 :     PQExpBuffer labelq = createPQExpBuffer();
    3141         124 :     PGconn     *conn = GetConnection(fout);
    3142             :     PGresult   *res;
    3143             :     int         i_tableoid,
    3144             :                 i_oid,
    3145             :                 i_datname,
    3146             :                 i_datdba,
    3147             :                 i_encoding,
    3148             :                 i_datlocprovider,
    3149             :                 i_collate,
    3150             :                 i_ctype,
    3151             :                 i_datlocale,
    3152             :                 i_daticurules,
    3153             :                 i_frozenxid,
    3154             :                 i_minmxid,
    3155             :                 i_datacl,
    3156             :                 i_acldefault,
    3157             :                 i_datistemplate,
    3158             :                 i_datconnlimit,
    3159             :                 i_datcollversion,
    3160             :                 i_tablespace;
    3161             :     CatalogId   dbCatId;
    3162             :     DumpId      dbDumpId;
    3163             :     DumpableAcl dbdacl;
    3164             :     const char *datname,
    3165             :                *dba,
    3166             :                *encoding,
    3167             :                *datlocprovider,
    3168             :                *collate,
    3169             :                *ctype,
    3170             :                *locale,
    3171             :                *icurules,
    3172             :                *datistemplate,
    3173             :                *datconnlimit,
    3174             :                *tablespace;
    3175             :     uint32      frozenxid,
    3176             :                 minmxid;
    3177             :     char       *qdatname;
    3178             : 
    3179         124 :     pg_log_info("saving database definition");
    3180             : 
    3181             :     /*
    3182             :      * Fetch the database-level properties for this database.
    3183             :      */
    3184         124 :     appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
    3185             :                          "datdba, "
    3186             :                          "pg_encoding_to_char(encoding) AS encoding, "
    3187             :                          "datcollate, datctype, datfrozenxid, "
    3188             :                          "datacl, acldefault('d', datdba) AS acldefault, "
    3189             :                          "datistemplate, datconnlimit, ");
    3190         124 :     if (fout->remoteVersion >= 90300)
    3191         124 :         appendPQExpBufferStr(dbQry, "datminmxid, ");
    3192             :     else
    3193           0 :         appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
    3194         124 :     if (fout->remoteVersion >= 170000)
    3195         124 :         appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
    3196           0 :     else if (fout->remoteVersion >= 150000)
    3197           0 :         appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
    3198             :     else
    3199           0 :         appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
    3200         124 :     if (fout->remoteVersion >= 160000)
    3201         124 :         appendPQExpBufferStr(dbQry, "daticurules, ");
    3202             :     else
    3203           0 :         appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
    3204         124 :     appendPQExpBufferStr(dbQry,
    3205             :                          "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
    3206             :                          "shobj_description(oid, 'pg_database') AS description "
    3207             :                          "FROM pg_database "
    3208             :                          "WHERE datname = current_database()");
    3209             : 
    3210         124 :     res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
    3211             : 
    3212         124 :     i_tableoid = PQfnumber(res, "tableoid");
    3213         124 :     i_oid = PQfnumber(res, "oid");
    3214         124 :     i_datname = PQfnumber(res, "datname");
    3215         124 :     i_datdba = PQfnumber(res, "datdba");
    3216         124 :     i_encoding = PQfnumber(res, "encoding");
    3217         124 :     i_datlocprovider = PQfnumber(res, "datlocprovider");
    3218         124 :     i_collate = PQfnumber(res, "datcollate");
    3219         124 :     i_ctype = PQfnumber(res, "datctype");
    3220         124 :     i_datlocale = PQfnumber(res, "datlocale");
    3221         124 :     i_daticurules = PQfnumber(res, "daticurules");
    3222         124 :     i_frozenxid = PQfnumber(res, "datfrozenxid");
    3223         124 :     i_minmxid = PQfnumber(res, "datminmxid");
    3224         124 :     i_datacl = PQfnumber(res, "datacl");
    3225         124 :     i_acldefault = PQfnumber(res, "acldefault");
    3226         124 :     i_datistemplate = PQfnumber(res, "datistemplate");
    3227         124 :     i_datconnlimit = PQfnumber(res, "datconnlimit");
    3228         124 :     i_datcollversion = PQfnumber(res, "datcollversion");
    3229         124 :     i_tablespace = PQfnumber(res, "tablespace");
    3230             : 
    3231         124 :     dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
    3232         124 :     dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
    3233         124 :     datname = PQgetvalue(res, 0, i_datname);
    3234         124 :     dba = getRoleName(PQgetvalue(res, 0, i_datdba));
    3235         124 :     encoding = PQgetvalue(res, 0, i_encoding);
    3236         124 :     datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
    3237         124 :     collate = PQgetvalue(res, 0, i_collate);
    3238         124 :     ctype = PQgetvalue(res, 0, i_ctype);
    3239         124 :     if (!PQgetisnull(res, 0, i_datlocale))
    3240          28 :         locale = PQgetvalue(res, 0, i_datlocale);
    3241             :     else
    3242          96 :         locale = NULL;
    3243         124 :     if (!PQgetisnull(res, 0, i_daticurules))
    3244           0 :         icurules = PQgetvalue(res, 0, i_daticurules);
    3245             :     else
    3246         124 :         icurules = NULL;
    3247         124 :     frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
    3248         124 :     minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
    3249         124 :     dbdacl.acl = PQgetvalue(res, 0, i_datacl);
    3250         124 :     dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
    3251         124 :     datistemplate = PQgetvalue(res, 0, i_datistemplate);
    3252         124 :     datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
    3253         124 :     tablespace = PQgetvalue(res, 0, i_tablespace);
    3254             : 
    3255         124 :     qdatname = pg_strdup(fmtId(datname));
    3256             : 
    3257             :     /*
    3258             :      * Prepare the CREATE DATABASE command.  We must specify OID (if we want
    3259             :      * to preserve that), as well as the encoding, locale, and tablespace
    3260             :      * since those can't be altered later.  Other DB properties are left to
    3261             :      * the DATABASE PROPERTIES entry, so that they can be applied after
    3262             :      * reconnecting to the target DB.
    3263             :      *
    3264             :      * For binary upgrade, we use the FILE_COPY strategy because testing has
    3265             :      * shown it to be faster.  When the server is in binary upgrade mode, it
    3266             :      * will also skip the checkpoints this strategy ordinarily performs.
    3267             :      */
    3268         124 :     if (dopt->binary_upgrade)
    3269             :     {
    3270          30 :         appendPQExpBuffer(creaQry,
    3271             :                           "CREATE DATABASE %s WITH TEMPLATE = template0 "
    3272             :                           "OID = %u STRATEGY = FILE_COPY",
    3273             :                           qdatname, dbCatId.oid);
    3274             :     }
    3275             :     else
    3276             :     {
    3277          94 :         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
    3278             :                           qdatname);
    3279             :     }
    3280         124 :     if (strlen(encoding) > 0)
    3281             :     {
    3282         124 :         appendPQExpBufferStr(creaQry, " ENCODING = ");
    3283         124 :         appendStringLiteralAH(creaQry, encoding, fout);
    3284             :     }
    3285             : 
    3286         124 :     appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
    3287         124 :     if (datlocprovider[0] == 'b')
    3288          28 :         appendPQExpBufferStr(creaQry, "builtin");
    3289          96 :     else if (datlocprovider[0] == 'c')
    3290          96 :         appendPQExpBufferStr(creaQry, "libc");
    3291           0 :     else if (datlocprovider[0] == 'i')
    3292           0 :         appendPQExpBufferStr(creaQry, "icu");
    3293             :     else
    3294           0 :         pg_fatal("unrecognized locale provider: %s",
    3295             :                  datlocprovider);
    3296             : 
    3297         124 :     if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
    3298             :     {
    3299         124 :         appendPQExpBufferStr(creaQry, " LOCALE = ");
    3300         124 :         appendStringLiteralAH(creaQry, collate, fout);
    3301             :     }
    3302             :     else
    3303             :     {
    3304           0 :         if (strlen(collate) > 0)
    3305             :         {
    3306           0 :             appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
    3307           0 :             appendStringLiteralAH(creaQry, collate, fout);
    3308             :         }
    3309           0 :         if (strlen(ctype) > 0)
    3310             :         {
    3311           0 :             appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
    3312           0 :             appendStringLiteralAH(creaQry, ctype, fout);
    3313             :         }
    3314             :     }
    3315         124 :     if (locale)
    3316             :     {
    3317          28 :         if (datlocprovider[0] == 'b')
    3318          28 :             appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
    3319             :         else
    3320           0 :             appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
    3321             : 
    3322          28 :         appendStringLiteralAH(creaQry, locale, fout);
    3323             :     }
    3324             : 
    3325         124 :     if (icurules)
    3326             :     {
    3327           0 :         appendPQExpBufferStr(creaQry, " ICU_RULES = ");
    3328           0 :         appendStringLiteralAH(creaQry, icurules, fout);
    3329             :     }
    3330             : 
    3331             :     /*
    3332             :      * For binary upgrade, carry over the collation version.  For normal
    3333             :      * dump/restore, omit the version, so that it is computed upon restore.
    3334             :      */
    3335         124 :     if (dopt->binary_upgrade)
    3336             :     {
    3337          30 :         if (!PQgetisnull(res, 0, i_datcollversion))
    3338             :         {
    3339          30 :             appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
    3340          30 :             appendStringLiteralAH(creaQry,
    3341             :                                   PQgetvalue(res, 0, i_datcollversion),
    3342             :                                   fout);
    3343             :         }
    3344             :     }
    3345             : 
    3346             :     /*
    3347             :      * Note: looking at dopt->outputNoTablespaces here is completely the wrong
    3348             :      * thing; the decision whether to specify a tablespace should be left till
    3349             :      * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
    3350             :      * label the DATABASE entry with the tablespace and let the normal
    3351             :      * tablespace selection logic work ... but CREATE DATABASE doesn't pay
    3352             :      * attention to default_tablespace, so that won't work.
    3353             :      */
    3354         124 :     if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
    3355           0 :         !dopt->outputNoTablespaces)
    3356           0 :         appendPQExpBuffer(creaQry, " TABLESPACE = %s",
    3357             :                           fmtId(tablespace));
    3358         124 :     appendPQExpBufferStr(creaQry, ";\n");
    3359             : 
    3360         124 :     appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
    3361             :                       qdatname);
    3362             : 
    3363         124 :     dbDumpId = createDumpId();
    3364             : 
    3365         124 :     ArchiveEntry(fout,
    3366             :                  dbCatId,       /* catalog ID */
    3367             :                  dbDumpId,      /* dump ID */
    3368         124 :                  ARCHIVE_OPTS(.tag = datname,
    3369             :                               .owner = dba,
    3370             :                               .description = "DATABASE",
    3371             :                               .section = SECTION_PRE_DATA,
    3372             :                               .createStmt = creaQry->data,
    3373             :                               .dropStmt = delQry->data));
    3374             : 
    3375             :     /* Compute correct tag for archive entry */
    3376         124 :     appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
    3377             : 
    3378             :     /* Dump DB comment if any */
    3379             :     {
    3380             :         /*
    3381             :          * 8.2 and up keep comments on shared objects in a shared table, so we
    3382             :          * cannot use the dumpComment() code used for other database objects.
    3383             :          * Be careful that the ArchiveEntry parameters match that function.
    3384             :          */
    3385         124 :         char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
    3386             : 
    3387         124 :         if (comment && *comment && !dopt->no_comments)
    3388             :         {
    3389          54 :             resetPQExpBuffer(dbQry);
    3390             : 
    3391             :             /*
    3392             :              * Generates warning when loaded into a differently-named
    3393             :              * database.
    3394             :              */
    3395          54 :             appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
    3396          54 :             appendStringLiteralAH(dbQry, comment, fout);
    3397          54 :             appendPQExpBufferStr(dbQry, ";\n");
    3398             : 
    3399          54 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3400          54 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3401             :                                       .owner = dba,
    3402             :                                       .description = "COMMENT",
    3403             :                                       .section = SECTION_NONE,
    3404             :                                       .createStmt = dbQry->data,
    3405             :                                       .deps = &dbDumpId,
    3406             :                                       .nDeps = 1));
    3407             :         }
    3408             :     }
    3409             : 
    3410             :     /* Dump DB security label, if enabled */
    3411         124 :     if (!dopt->no_security_labels)
    3412             :     {
    3413             :         PGresult   *shres;
    3414             :         PQExpBuffer seclabelQry;
    3415             : 
    3416         124 :         seclabelQry = createPQExpBuffer();
    3417             : 
    3418         124 :         buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
    3419         124 :         shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
    3420         124 :         resetPQExpBuffer(seclabelQry);
    3421         124 :         emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
    3422         124 :         if (seclabelQry->len > 0)
    3423           0 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3424           0 :                          ARCHIVE_OPTS(.tag = labelq->data,
    3425             :                                       .owner = dba,
    3426             :                                       .description = "SECURITY LABEL",
    3427             :                                       .section = SECTION_NONE,
    3428             :                                       .createStmt = seclabelQry->data,
    3429             :                                       .deps = &dbDumpId,
    3430             :                                       .nDeps = 1));
    3431         124 :         destroyPQExpBuffer(seclabelQry);
    3432         124 :         PQclear(shres);
    3433             :     }
    3434             : 
    3435             :     /*
    3436             :      * Dump ACL if any.  Note that we do not support initial privileges
    3437             :      * (pg_init_privs) on databases.
    3438             :      */
    3439         124 :     dbdacl.privtype = 0;
    3440         124 :     dbdacl.initprivs = NULL;
    3441             : 
    3442         124 :     dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
    3443             :             qdatname, NULL, NULL,
    3444             :             NULL, dba, &dbdacl);
    3445             : 
    3446             :     /*
    3447             :      * Now construct a DATABASE PROPERTIES archive entry to restore any
    3448             :      * non-default database-level properties.  (The reason this must be
    3449             :      * separate is that we cannot put any additional commands into the TOC
    3450             :      * entry that has CREATE DATABASE.  pg_restore would execute such a group
    3451             :      * in an implicit transaction block, and the backend won't allow CREATE
    3452             :      * DATABASE in that context.)
    3453             :      */
    3454         124 :     resetPQExpBuffer(creaQry);
    3455         124 :     resetPQExpBuffer(delQry);
    3456             : 
    3457         124 :     if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
    3458           0 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
    3459             :                           qdatname, datconnlimit);
    3460             : 
    3461         124 :     if (strcmp(datistemplate, "t") == 0)
    3462             :     {
    3463          10 :         appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
    3464             :                           qdatname);
    3465             : 
    3466             :         /*
    3467             :          * The backend won't accept DROP DATABASE on a template database.  We
    3468             :          * can deal with that by removing the template marking before the DROP
    3469             :          * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
    3470             :          * since no such command is currently supported, fake it with a direct
    3471             :          * UPDATE on pg_database.
    3472             :          */
    3473          10 :         appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
    3474             :                              "SET datistemplate = false WHERE datname = ");
    3475          10 :         appendStringLiteralAH(delQry, datname, fout);
    3476          10 :         appendPQExpBufferStr(delQry, ";\n");
    3477             :     }
    3478             : 
    3479             :     /*
    3480             :      * We do not restore pg_database.dathasloginevt because it is set
    3481             :      * automatically on login event trigger creation.
    3482             :      */
    3483             : 
    3484             :     /* Add database-specific SET options */
    3485         124 :     dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
    3486             : 
    3487             :     /*
    3488             :      * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
    3489             :      * entry, too, for lack of a better place.
    3490             :      */
    3491         124 :     if (dopt->binary_upgrade)
    3492             :     {
    3493          30 :         appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
    3494          30 :         appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
    3495             :                           "SET datfrozenxid = '%u', datminmxid = '%u'\n"
    3496             :                           "WHERE datname = ",
    3497             :                           frozenxid, minmxid);
    3498          30 :         appendStringLiteralAH(creaQry, datname, fout);
    3499          30 :         appendPQExpBufferStr(creaQry, ";\n");
    3500             :     }
    3501             : 
    3502         124 :     if (creaQry->len > 0)
    3503          38 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3504          38 :                      ARCHIVE_OPTS(.tag = datname,
    3505             :                                   .owner = dba,
    3506             :                                   .description = "DATABASE PROPERTIES",
    3507             :                                   .section = SECTION_PRE_DATA,
    3508             :                                   .createStmt = creaQry->data,
    3509             :                                   .dropStmt = delQry->data,
    3510             :                                   .deps = &dbDumpId));
    3511             : 
    3512             :     /*
    3513             :      * pg_largeobject comes from the old system intact, so set its
    3514             :      * relfrozenxids, relminmxids and relfilenode.
    3515             :      */
    3516         124 :     if (dopt->binary_upgrade)
    3517             :     {
    3518             :         PGresult   *lo_res;
    3519          30 :         PQExpBuffer loFrozenQry = createPQExpBuffer();
    3520          30 :         PQExpBuffer loOutQry = createPQExpBuffer();
    3521          30 :         PQExpBuffer loHorizonQry = createPQExpBuffer();
    3522             :         int         ii_relfrozenxid,
    3523             :                     ii_relfilenode,
    3524             :                     ii_oid,
    3525             :                     ii_relminmxid;
    3526             : 
    3527             :         /*
    3528             :          * pg_largeobject
    3529             :          */
    3530          30 :         if (fout->remoteVersion >= 90300)
    3531          30 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
    3532             :                               "FROM pg_catalog.pg_class\n"
    3533             :                               "WHERE oid IN (%u, %u);\n",
    3534             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3535             :         else
    3536           0 :             appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
    3537             :                               "FROM pg_catalog.pg_class\n"
    3538             :                               "WHERE oid IN (%u, %u);\n",
    3539             :                               LargeObjectRelationId, LargeObjectLOidPNIndexId);
    3540             : 
    3541          30 :         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
    3542             : 
    3543          30 :         ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
    3544          30 :         ii_relminmxid = PQfnumber(lo_res, "relminmxid");
    3545          30 :         ii_relfilenode = PQfnumber(lo_res, "relfilenode");
    3546          30 :         ii_oid = PQfnumber(lo_res, "oid");
    3547             : 
    3548          30 :         appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
    3549          30 :         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
    3550          90 :         for (int i = 0; i < PQntuples(lo_res); ++i)
    3551             :         {
    3552             :             Oid         oid;
    3553             :             RelFileNumber relfilenumber;
    3554             : 
    3555          60 :             appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
    3556             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
    3557             :                               "WHERE oid = %u;\n",
    3558          60 :                               atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
    3559          60 :                               atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
    3560          60 :                               atooid(PQgetvalue(lo_res, i, ii_oid)));
    3561             : 
    3562          60 :             oid = atooid(PQgetvalue(lo_res, i, ii_oid));
    3563          60 :             relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
    3564             : 
    3565          60 :             if (oid == LargeObjectRelationId)
    3566          30 :                 appendPQExpBuffer(loOutQry,
    3567             :                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    3568             :                                   relfilenumber);
    3569          30 :             else if (oid == LargeObjectLOidPNIndexId)
    3570          30 :                 appendPQExpBuffer(loOutQry,
    3571             :                                   "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    3572             :                                   relfilenumber);
    3573             :         }
    3574             : 
    3575          30 :         appendPQExpBufferStr(loOutQry,
    3576             :                              "TRUNCATE pg_catalog.pg_largeobject;\n");
    3577          30 :         appendPQExpBufferStr(loOutQry, loHorizonQry->data);
    3578             : 
    3579          30 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
    3580          30 :                      ARCHIVE_OPTS(.tag = "pg_largeobject",
    3581             :                                   .description = "pg_largeobject",
    3582             :                                   .section = SECTION_PRE_DATA,
    3583             :                                   .createStmt = loOutQry->data));
    3584             : 
    3585          30 :         PQclear(lo_res);
    3586             : 
    3587          30 :         destroyPQExpBuffer(loFrozenQry);
    3588          30 :         destroyPQExpBuffer(loHorizonQry);
    3589          30 :         destroyPQExpBuffer(loOutQry);
    3590             :     }
    3591             : 
    3592         124 :     PQclear(res);
    3593             : 
    3594         124 :     free(qdatname);
    3595         124 :     destroyPQExpBuffer(dbQry);
    3596         124 :     destroyPQExpBuffer(delQry);
    3597         124 :     destroyPQExpBuffer(creaQry);
    3598         124 :     destroyPQExpBuffer(labelq);
    3599         124 : }
    3600             : 
    3601             : /*
    3602             :  * Collect any database-specific or role-and-database-specific SET options
    3603             :  * for this database, and append them to outbuf.
    3604             :  */
    3605             : static void
    3606         124 : dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
    3607             :                    const char *dbname, Oid dboid)
    3608             : {
    3609         124 :     PGconn     *conn = GetConnection(AH);
    3610         124 :     PQExpBuffer buf = createPQExpBuffer();
    3611             :     PGresult   *res;
    3612             : 
    3613             :     /* First collect database-specific options */
    3614         124 :     printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
    3615             :                       "WHERE setrole = 0 AND setdatabase = '%u'::oid",
    3616             :                       dboid);
    3617             : 
    3618         124 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3619             : 
    3620         184 :     for (int i = 0; i < PQntuples(res); i++)
    3621          60 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 0),
    3622             :                                "DATABASE", dbname, NULL, NULL,
    3623             :                                outbuf);
    3624             : 
    3625         124 :     PQclear(res);
    3626             : 
    3627             :     /* Now look for role-and-database-specific options */
    3628         124 :     printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
    3629             :                       "FROM pg_db_role_setting s, pg_roles r "
    3630             :                       "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
    3631             :                       dboid);
    3632             : 
    3633         124 :     res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
    3634             : 
    3635         124 :     for (int i = 0; i < PQntuples(res); i++)
    3636           0 :         makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
    3637           0 :                                "ROLE", PQgetvalue(res, i, 0),
    3638             :                                "DATABASE", dbname,
    3639             :                                outbuf);
    3640             : 
    3641         124 :     PQclear(res);
    3642             : 
    3643         124 :     destroyPQExpBuffer(buf);
    3644         124 : }
    3645             : 
    3646             : /*
    3647             :  * dumpEncoding: put the correct encoding into the archive
    3648             :  */
    3649             : static void
    3650         320 : dumpEncoding(Archive *AH)
    3651             : {
    3652         320 :     const char *encname = pg_encoding_to_char(AH->encoding);
    3653         320 :     PQExpBuffer qry = createPQExpBuffer();
    3654             : 
    3655         320 :     pg_log_info("saving encoding = %s", encname);
    3656             : 
    3657         320 :     appendPQExpBufferStr(qry, "SET client_encoding = ");
    3658         320 :     appendStringLiteralAH(qry, encname, AH);
    3659         320 :     appendPQExpBufferStr(qry, ";\n");
    3660             : 
    3661         320 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3662         320 :                  ARCHIVE_OPTS(.tag = "ENCODING",
    3663             :                               .description = "ENCODING",
    3664             :                               .section = SECTION_PRE_DATA,
    3665             :                               .createStmt = qry->data));
    3666             : 
    3667         320 :     destroyPQExpBuffer(qry);
    3668         320 : }
    3669             : 
    3670             : 
    3671             : /*
    3672             :  * dumpStdStrings: put the correct escape string behavior into the archive
    3673             :  */
    3674             : static void
    3675         320 : dumpStdStrings(Archive *AH)
    3676             : {
    3677         320 :     const char *stdstrings = AH->std_strings ? "on" : "off";
    3678         320 :     PQExpBuffer qry = createPQExpBuffer();
    3679             : 
    3680         320 :     pg_log_info("saving \"standard_conforming_strings = %s\"",
    3681             :                 stdstrings);
    3682             : 
    3683         320 :     appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
    3684             :                       stdstrings);
    3685             : 
    3686         320 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3687         320 :                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
    3688             :                               .description = "STDSTRINGS",
    3689             :                               .section = SECTION_PRE_DATA,
    3690             :                               .createStmt = qry->data));
    3691             : 
    3692         320 :     destroyPQExpBuffer(qry);
    3693         320 : }
    3694             : 
    3695             : /*
    3696             :  * dumpSearchPath: record the active search_path in the archive
    3697             :  */
    3698             : static void
    3699         320 : dumpSearchPath(Archive *AH)
    3700             : {
    3701         320 :     PQExpBuffer qry = createPQExpBuffer();
    3702         320 :     PQExpBuffer path = createPQExpBuffer();
    3703             :     PGresult   *res;
    3704         320 :     char      **schemanames = NULL;
    3705         320 :     int         nschemanames = 0;
    3706             :     int         i;
    3707             : 
    3708             :     /*
    3709             :      * We use the result of current_schemas(), not the search_path GUC,
    3710             :      * because that might contain wildcards such as "$user", which won't
    3711             :      * necessarily have the same value during restore.  Also, this way avoids
    3712             :      * listing schemas that may appear in search_path but not actually exist,
    3713             :      * which seems like a prudent exclusion.
    3714             :      */
    3715         320 :     res = ExecuteSqlQueryForSingleRow(AH,
    3716             :                                       "SELECT pg_catalog.current_schemas(false)");
    3717             : 
    3718         320 :     if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
    3719           0 :         pg_fatal("could not parse result of current_schemas()");
    3720             : 
    3721             :     /*
    3722             :      * We use set_config(), not a simple "SET search_path" command, because
    3723             :      * the latter has less-clean behavior if the search path is empty.  While
    3724             :      * that's likely to get fixed at some point, it seems like a good idea to
    3725             :      * be as backwards-compatible as possible in what we put into archives.
    3726             :      */
    3727         320 :     for (i = 0; i < nschemanames; i++)
    3728             :     {
    3729           0 :         if (i > 0)
    3730           0 :             appendPQExpBufferStr(path, ", ");
    3731           0 :         appendPQExpBufferStr(path, fmtId(schemanames[i]));
    3732             :     }
    3733             : 
    3734         320 :     appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
    3735         320 :     appendStringLiteralAH(qry, path->data, AH);
    3736         320 :     appendPQExpBufferStr(qry, ", false);\n");
    3737             : 
    3738         320 :     pg_log_info("saving \"search_path = %s\"", path->data);
    3739             : 
    3740         320 :     ArchiveEntry(AH, nilCatalogId, createDumpId(),
    3741         320 :                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
    3742             :                               .description = "SEARCHPATH",
    3743             :                               .section = SECTION_PRE_DATA,
    3744             :                               .createStmt = qry->data));
    3745             : 
    3746             :     /* Also save it in AH->searchpath, in case we're doing plain text dump */
    3747         320 :     AH->searchpath = pg_strdup(qry->data);
    3748             : 
    3749         320 :     free(schemanames);
    3750         320 :     PQclear(res);
    3751         320 :     destroyPQExpBuffer(qry);
    3752         320 :     destroyPQExpBuffer(path);
    3753         320 : }
    3754             : 
    3755             : 
    3756             : /*
    3757             :  * getLOs:
    3758             :  *  Collect schema-level data about large objects
    3759             :  */
    3760             : static void
    3761         264 : getLOs(Archive *fout)
    3762             : {
    3763         264 :     DumpOptions *dopt = fout->dopt;
    3764         264 :     PQExpBuffer loQry = createPQExpBuffer();
    3765             :     PGresult   *res;
    3766             :     int         ntups;
    3767             :     int         i;
    3768             :     int         n;
    3769             :     int         i_oid;
    3770             :     int         i_lomowner;
    3771             :     int         i_lomacl;
    3772             :     int         i_acldefault;
    3773             : 
    3774         264 :     pg_log_info("reading large objects");
    3775             : 
    3776             :     /*
    3777             :      * Fetch LO OIDs and owner/ACL data.  Order the data so that all the blobs
    3778             :      * with the same owner/ACL appear together.
    3779             :      */
    3780         264 :     appendPQExpBufferStr(loQry,
    3781             :                          "SELECT oid, lomowner, lomacl, "
    3782             :                          "acldefault('L', lomowner) AS acldefault "
    3783             :                          "FROM pg_largeobject_metadata "
    3784             :                          "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
    3785             : 
    3786         264 :     res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
    3787             : 
    3788         264 :     i_oid = PQfnumber(res, "oid");
    3789         264 :     i_lomowner = PQfnumber(res, "lomowner");
    3790         264 :     i_lomacl = PQfnumber(res, "lomacl");
    3791         264 :     i_acldefault = PQfnumber(res, "acldefault");
    3792             : 
    3793         264 :     ntups = PQntuples(res);
    3794             : 
    3795             :     /*
    3796             :      * Group the blobs into suitably-sized groups that have the same owner and
    3797             :      * ACL setting, and build a metadata and a data DumpableObject for each
    3798             :      * group.  (If we supported initprivs for blobs, we'd have to insist that
    3799             :      * groups also share initprivs settings, since the DumpableObject only has
    3800             :      * room for one.)  i is the index of the first tuple in the current group,
    3801             :      * and n is the number of tuples we include in the group.
    3802             :      */
    3803         418 :     for (i = 0; i < ntups; i += n)
    3804             :     {
    3805         154 :         Oid         thisoid = atooid(PQgetvalue(res, i, i_oid));
    3806         154 :         char       *thisowner = PQgetvalue(res, i, i_lomowner);
    3807         154 :         char       *thisacl = PQgetvalue(res, i, i_lomacl);
    3808             :         LoInfo     *loinfo;
    3809             :         DumpableObject *lodata;
    3810             :         char        namebuf[64];
    3811             : 
    3812             :         /* Scan to find first tuple not to be included in group */
    3813         154 :         n = 1;
    3814         174 :         while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
    3815             :         {
    3816          92 :             if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
    3817          92 :                 strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
    3818             :                 break;
    3819          20 :             n++;
    3820             :         }
    3821             : 
    3822             :         /* Build the metadata DumpableObject */
    3823         154 :         loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
    3824             : 
    3825         154 :         loinfo->dobj.objType = DO_LARGE_OBJECT;
    3826         154 :         loinfo->dobj.catId.tableoid = LargeObjectRelationId;
    3827         154 :         loinfo->dobj.catId.oid = thisoid;
    3828         154 :         AssignDumpId(&loinfo->dobj);
    3829             : 
    3830         154 :         if (n > 1)
    3831          10 :             snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
    3832          10 :                      atooid(PQgetvalue(res, i + n - 1, i_oid)));
    3833             :         else
    3834         144 :             snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
    3835         154 :         loinfo->dobj.name = pg_strdup(namebuf);
    3836         154 :         loinfo->dacl.acl = pg_strdup(thisacl);
    3837         154 :         loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    3838         154 :         loinfo->dacl.privtype = 0;
    3839         154 :         loinfo->dacl.initprivs = NULL;
    3840         154 :         loinfo->rolname = getRoleName(thisowner);
    3841         154 :         loinfo->numlos = n;
    3842         154 :         loinfo->looids[0] = thisoid;
    3843             :         /* Collect OIDs of the remaining blobs in this group */
    3844         174 :         for (int k = 1; k < n; k++)
    3845             :         {
    3846             :             CatalogId   extraID;
    3847             : 
    3848          20 :             loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
    3849             : 
    3850             :             /* Make sure we can look up loinfo by any of the blobs' OIDs */
    3851          20 :             extraID.tableoid = LargeObjectRelationId;
    3852          20 :             extraID.oid = loinfo->looids[k];
    3853          20 :             recordAdditionalCatalogID(extraID, &loinfo->dobj);
    3854             :         }
    3855             : 
    3856             :         /* LOs have data */
    3857         154 :         loinfo->dobj.components |= DUMP_COMPONENT_DATA;
    3858             : 
    3859             :         /* Mark whether LO group has a non-empty ACL */
    3860         154 :         if (!PQgetisnull(res, i, i_lomacl))
    3861          72 :             loinfo->dobj.components |= DUMP_COMPONENT_ACL;
    3862             : 
    3863             :         /*
    3864             :          * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
    3865             :          * as it will be copied by pg_upgrade, which simply copies the
    3866             :          * pg_largeobject table. We *do* however dump out anything but the
    3867             :          * data, as pg_upgrade copies just pg_largeobject, but not
    3868             :          * pg_largeobject_metadata, after the dump is restored.
    3869             :          */
    3870         154 :         if (dopt->binary_upgrade)
    3871           6 :             loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
    3872             : 
    3873             :         /*
    3874             :          * Create a "BLOBS" data item for the group, too. This is just a
    3875             :          * placeholder for sorting; it carries no data now.
    3876             :          */
    3877         154 :         lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
    3878         154 :         lodata->objType = DO_LARGE_OBJECT_DATA;
    3879         154 :         lodata->catId = nilCatalogId;
    3880         154 :         AssignDumpId(lodata);
    3881         154 :         lodata->name = pg_strdup(namebuf);
    3882         154 :         lodata->components |= DUMP_COMPONENT_DATA;
    3883             :         /* Set up explicit dependency from data to metadata */
    3884         154 :         lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    3885         154 :         lodata->dependencies[0] = loinfo->dobj.dumpId;
    3886         154 :         lodata->nDeps = lodata->allocDeps = 1;
    3887             :     }
    3888             : 
    3889         264 :     PQclear(res);
    3890         264 :     destroyPQExpBuffer(loQry);
    3891         264 : }
    3892             : 
    3893             : /*
    3894             :  * dumpLO
    3895             :  *
    3896             :  * dump the definition (metadata) of the given large object group
    3897             :  */
    3898             : static void
    3899         154 : dumpLO(Archive *fout, const LoInfo *loinfo)
    3900             : {
    3901         154 :     PQExpBuffer cquery = createPQExpBuffer();
    3902             : 
    3903             :     /*
    3904             :      * The "definition" is just a newline-separated list of OIDs.  We need to
    3905             :      * put something into the dropStmt too, but it can just be a comment.
    3906             :      */
    3907         328 :     for (int i = 0; i < loinfo->numlos; i++)
    3908         174 :         appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
    3909             : 
    3910         154 :     if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    3911         154 :         ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
    3912         154 :                      ARCHIVE_OPTS(.tag = loinfo->dobj.name,
    3913             :                                   .owner = loinfo->rolname,
    3914             :                                   .description = "BLOB METADATA",
    3915             :                                   .section = SECTION_DATA,
    3916             :                                   .createStmt = cquery->data,
    3917             :                                   .dropStmt = "-- dummy"));
    3918             : 
    3919             :     /*
    3920             :      * Dump per-blob comments and seclabels if any.  We assume these are rare
    3921             :      * enough that it's okay to generate retail TOC entries for them.
    3922             :      */
    3923         154 :     if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
    3924             :                              DUMP_COMPONENT_SECLABEL))
    3925             :     {
    3926         184 :         for (int i = 0; i < loinfo->numlos; i++)
    3927             :         {
    3928             :             CatalogId   catId;
    3929             :             char        namebuf[32];
    3930             : 
    3931             :             /* Build identifying info for this blob */
    3932         102 :             catId.tableoid = loinfo->dobj.catId.tableoid;
    3933         102 :             catId.oid = loinfo->looids[i];
    3934         102 :             snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
    3935             : 
    3936         102 :             if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    3937         102 :                 dumpComment(fout, "LARGE OBJECT", namebuf,
    3938             :                             NULL, loinfo->rolname,
    3939             :                             catId, 0, loinfo->dobj.dumpId);
    3940             : 
    3941         102 :             if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    3942           0 :                 dumpSecLabel(fout, "LARGE OBJECT", namebuf,
    3943             :                              NULL, loinfo->rolname,
    3944             :                              catId, 0, loinfo->dobj.dumpId);
    3945             :         }
    3946             :     }
    3947             : 
    3948             :     /*
    3949             :      * Dump the ACLs if any (remember that all blobs in the group will have
    3950             :      * the same ACL).  If there's just one blob, dump a simple ACL entry; if
    3951             :      * there's more, make a "LARGE OBJECTS" entry that really contains only
    3952             :      * the ACL for the first blob.  _printTocEntry() will be cued by the tag
    3953             :      * string to emit a mutated version for each blob.
    3954             :      */
    3955         154 :     if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
    3956             :     {
    3957             :         char        namebuf[32];
    3958             : 
    3959             :         /* Build identifying info for the first blob */
    3960          72 :         snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
    3961             : 
    3962          72 :         if (loinfo->numlos > 1)
    3963             :         {
    3964             :             char        tagbuf[64];
    3965             : 
    3966           0 :             snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
    3967           0 :                      loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
    3968             : 
    3969           0 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    3970             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    3971             :                     tagbuf, loinfo->rolname, &loinfo->dacl);
    3972             :         }
    3973             :         else
    3974             :         {
    3975          72 :             dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
    3976             :                     "LARGE OBJECT", namebuf, NULL, NULL,
    3977             :                     NULL, loinfo->rolname, &loinfo->dacl);
    3978             :         }
    3979             :     }
    3980             : 
    3981         154 :     destroyPQExpBuffer(cquery);
    3982         154 : }
    3983             : 
    3984             : /*
    3985             :  * dumpLOs:
    3986             :  *  dump the data contents of the large objects in the given group
    3987             :  */
    3988             : static int
    3989         140 : dumpLOs(Archive *fout, const void *arg)
    3990             : {
    3991         140 :     const LoInfo *loinfo = (const LoInfo *) arg;
    3992         140 :     PGconn     *conn = GetConnection(fout);
    3993             :     char        buf[LOBBUFSIZE];
    3994             : 
    3995         140 :     pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
    3996             : 
    3997         296 :     for (int i = 0; i < loinfo->numlos; i++)
    3998             :     {
    3999         156 :         Oid         loOid = loinfo->looids[i];
    4000             :         int         loFd;
    4001             :         int         cnt;
    4002             : 
    4003             :         /* Open the LO */
    4004         156 :         loFd = lo_open(conn, loOid, INV_READ);
    4005         156 :         if (loFd == -1)
    4006           0 :             pg_fatal("could not open large object %u: %s",
    4007             :                      loOid, PQerrorMessage(conn));
    4008             : 
    4009         156 :         StartLO(fout, loOid);
    4010             : 
    4011             :         /* Now read it in chunks, sending data to archive */
    4012             :         do
    4013             :         {
    4014         238 :             cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
    4015         238 :             if (cnt < 0)
    4016           0 :                 pg_fatal("error reading large object %u: %s",
    4017             :                          loOid, PQerrorMessage(conn));
    4018             : 
    4019         238 :             WriteData(fout, buf, cnt);
    4020         238 :         } while (cnt > 0);
    4021             : 
    4022         156 :         lo_close(conn, loFd);
    4023             : 
    4024         156 :         EndLO(fout, loOid);
    4025             :     }
    4026             : 
    4027         140 :     return 1;
    4028             : }
    4029             : 
    4030             : /*
    4031             :  * getPolicies
    4032             :  *    get information about all RLS policies on dumpable tables.
    4033             :  */
    4034             : void
    4035         320 : getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
    4036             : {
    4037             :     PQExpBuffer query;
    4038             :     PQExpBuffer tbloids;
    4039             :     PGresult   *res;
    4040             :     PolicyInfo *polinfo;
    4041             :     int         i_oid;
    4042             :     int         i_tableoid;
    4043             :     int         i_polrelid;
    4044             :     int         i_polname;
    4045             :     int         i_polcmd;
    4046             :     int         i_polpermissive;
    4047             :     int         i_polroles;
    4048             :     int         i_polqual;
    4049             :     int         i_polwithcheck;
    4050             :     int         i,
    4051             :                 j,
    4052             :                 ntups;
    4053             : 
    4054             :     /* No policies before 9.5 */
    4055         320 :     if (fout->remoteVersion < 90500)
    4056           0 :         return;
    4057             : 
    4058         320 :     query = createPQExpBuffer();
    4059         320 :     tbloids = createPQExpBuffer();
    4060             : 
    4061             :     /*
    4062             :      * Identify tables of interest, and check which ones have RLS enabled.
    4063             :      */
    4064         320 :     appendPQExpBufferChar(tbloids, '{');
    4065       85060 :     for (i = 0; i < numTables; i++)
    4066             :     {
    4067       84740 :         TableInfo  *tbinfo = &tblinfo[i];
    4068             : 
    4069             :         /* Ignore row security on tables not to be dumped */
    4070       84740 :         if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
    4071       71522 :             continue;
    4072             : 
    4073             :         /* It can't have RLS or policies if it's not a table */
    4074       13218 :         if (tbinfo->relkind != RELKIND_RELATION &&
    4075        3894 :             tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
    4076        2806 :             continue;
    4077             : 
    4078             :         /* Add it to the list of table OIDs to be probed below */
    4079       10412 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    4080       10208 :             appendPQExpBufferChar(tbloids, ',');
    4081       10412 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    4082             : 
    4083             :         /* Is RLS enabled?  (That's separate from whether it has policies) */
    4084       10412 :         if (tbinfo->rowsec)
    4085             :         {
    4086         112 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4087             : 
    4088             :             /*
    4089             :              * We represent RLS being enabled on a table by creating a
    4090             :              * PolicyInfo object with null polname.
    4091             :              *
    4092             :              * Note: use tableoid 0 so that this object won't be mistaken for
    4093             :              * something that pg_depend entries apply to.
    4094             :              */
    4095         112 :             polinfo = pg_malloc(sizeof(PolicyInfo));
    4096         112 :             polinfo->dobj.objType = DO_POLICY;
    4097         112 :             polinfo->dobj.catId.tableoid = 0;
    4098         112 :             polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
    4099         112 :             AssignDumpId(&polinfo->dobj);
    4100         112 :             polinfo->dobj.namespace = tbinfo->dobj.namespace;
    4101         112 :             polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
    4102         112 :             polinfo->poltable = tbinfo;
    4103         112 :             polinfo->polname = NULL;
    4104         112 :             polinfo->polcmd = '\0';
    4105         112 :             polinfo->polpermissive = 0;
    4106         112 :             polinfo->polroles = NULL;
    4107         112 :             polinfo->polqual = NULL;
    4108         112 :             polinfo->polwithcheck = NULL;
    4109             :         }
    4110             :     }
    4111         320 :     appendPQExpBufferChar(tbloids, '}');
    4112             : 
    4113             :     /*
    4114             :      * Now, read all RLS policies belonging to the tables of interest, and
    4115             :      * create PolicyInfo objects for them.  (Note that we must filter the
    4116             :      * results server-side not locally, because we dare not apply pg_get_expr
    4117             :      * to tables we don't have lock on.)
    4118             :      */
    4119         320 :     pg_log_info("reading row-level security policies");
    4120             : 
    4121         320 :     printfPQExpBuffer(query,
    4122             :                       "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
    4123         320 :     if (fout->remoteVersion >= 100000)
    4124         320 :         appendPQExpBufferStr(query, "pol.polpermissive, ");
    4125             :     else
    4126           0 :         appendPQExpBufferStr(query, "'t' as polpermissive, ");
    4127         320 :     appendPQExpBuffer(query,
    4128             :                       "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
    4129             :                       "   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, "
    4130             :                       "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
    4131             :                       "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
    4132             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    4133             :                       "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
    4134             :                       tbloids->data);
    4135             : 
    4136         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4137             : 
    4138         320 :     ntups = PQntuples(res);
    4139         320 :     if (ntups > 0)
    4140             :     {
    4141          92 :         i_oid = PQfnumber(res, "oid");
    4142          92 :         i_tableoid = PQfnumber(res, "tableoid");
    4143          92 :         i_polrelid = PQfnumber(res, "polrelid");
    4144          92 :         i_polname = PQfnumber(res, "polname");
    4145          92 :         i_polcmd = PQfnumber(res, "polcmd");
    4146          92 :         i_polpermissive = PQfnumber(res, "polpermissive");
    4147          92 :         i_polroles = PQfnumber(res, "polroles");
    4148          92 :         i_polqual = PQfnumber(res, "polqual");
    4149          92 :         i_polwithcheck = PQfnumber(res, "polwithcheck");
    4150             : 
    4151          92 :         polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
    4152             : 
    4153         674 :         for (j = 0; j < ntups; j++)
    4154             :         {
    4155         582 :             Oid         polrelid = atooid(PQgetvalue(res, j, i_polrelid));
    4156         582 :             TableInfo  *tbinfo = findTableByOid(polrelid);
    4157             : 
    4158         582 :             tbinfo->dobj.components |= DUMP_COMPONENT_POLICY;
    4159             : 
    4160         582 :             polinfo[j].dobj.objType = DO_POLICY;
    4161         582 :             polinfo[j].dobj.catId.tableoid =
    4162         582 :                 atooid(PQgetvalue(res, j, i_tableoid));
    4163         582 :             polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    4164         582 :             AssignDumpId(&polinfo[j].dobj);
    4165         582 :             polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4166         582 :             polinfo[j].poltable = tbinfo;
    4167         582 :             polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
    4168         582 :             polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
    4169             : 
    4170         582 :             polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
    4171         582 :             polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
    4172             : 
    4173         582 :             if (PQgetisnull(res, j, i_polroles))
    4174         254 :                 polinfo[j].polroles = NULL;
    4175             :             else
    4176         328 :                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
    4177             : 
    4178         582 :             if (PQgetisnull(res, j, i_polqual))
    4179          82 :                 polinfo[j].polqual = NULL;
    4180             :             else
    4181         500 :                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
    4182             : 
    4183         582 :             if (PQgetisnull(res, j, i_polwithcheck))
    4184         306 :                 polinfo[j].polwithcheck = NULL;
    4185             :             else
    4186         276 :                 polinfo[j].polwithcheck
    4187         276 :                     = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
    4188             :         }
    4189             :     }
    4190             : 
    4191         320 :     PQclear(res);
    4192             : 
    4193         320 :     destroyPQExpBuffer(query);
    4194         320 :     destroyPQExpBuffer(tbloids);
    4195             : }
    4196             : 
    4197             : /*
    4198             :  * dumpPolicy
    4199             :  *    dump the definition of the given policy
    4200             :  */
    4201             : static void
    4202         694 : dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
    4203             : {
    4204         694 :     DumpOptions *dopt = fout->dopt;
    4205         694 :     TableInfo  *tbinfo = polinfo->poltable;
    4206             :     PQExpBuffer query;
    4207             :     PQExpBuffer delqry;
    4208             :     PQExpBuffer polprefix;
    4209             :     char       *qtabname;
    4210             :     const char *cmd;
    4211             :     char       *tag;
    4212             : 
    4213             :     /* Do nothing if not dumping schema */
    4214         694 :     if (!dopt->dumpSchema)
    4215          98 :         return;
    4216             : 
    4217             :     /*
    4218             :      * If polname is NULL, then this record is just indicating that ROW LEVEL
    4219             :      * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
    4220             :      * ROW LEVEL SECURITY.
    4221             :      */
    4222         596 :     if (polinfo->polname == NULL)
    4223             :     {
    4224          98 :         query = createPQExpBuffer();
    4225             : 
    4226          98 :         appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
    4227          98 :                           fmtQualifiedDumpable(tbinfo));
    4228             : 
    4229             :         /*
    4230             :          * We must emit the ROW SECURITY object's dependency on its table
    4231             :          * explicitly, because it will not match anything in pg_depend (unlike
    4232             :          * the case for other PolicyInfo objects).
    4233             :          */
    4234          98 :         if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4235          98 :             ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4236          98 :                          ARCHIVE_OPTS(.tag = polinfo->dobj.name,
    4237             :                                       .namespace = polinfo->dobj.namespace->dobj.name,
    4238             :                                       .owner = tbinfo->rolname,
    4239             :                                       .description = "ROW SECURITY",
    4240             :                                       .section = SECTION_POST_DATA,
    4241             :                                       .createStmt = query->data,
    4242             :                                       .deps = &(tbinfo->dobj.dumpId),
    4243             :                                       .nDeps = 1));
    4244             : 
    4245          98 :         destroyPQExpBuffer(query);
    4246          98 :         return;
    4247             :     }
    4248             : 
    4249         498 :     if (polinfo->polcmd == '*')
    4250         166 :         cmd = "";
    4251         332 :     else if (polinfo->polcmd == 'r')
    4252          88 :         cmd = " FOR SELECT";
    4253         244 :     else if (polinfo->polcmd == 'a')
    4254          68 :         cmd = " FOR INSERT";
    4255         176 :     else if (polinfo->polcmd == 'w')
    4256          88 :         cmd = " FOR UPDATE";
    4257          88 :     else if (polinfo->polcmd == 'd')
    4258          88 :         cmd = " FOR DELETE";
    4259             :     else
    4260           0 :         pg_fatal("unexpected policy command type: %c",
    4261             :                  polinfo->polcmd);
    4262             : 
    4263         498 :     query = createPQExpBuffer();
    4264         498 :     delqry = createPQExpBuffer();
    4265         498 :     polprefix = createPQExpBuffer();
    4266             : 
    4267         498 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
    4268             : 
    4269         498 :     appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
    4270             : 
    4271         498 :     appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
    4272         498 :                       !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
    4273             : 
    4274         498 :     if (polinfo->polroles != NULL)
    4275         272 :         appendPQExpBuffer(query, " TO %s", polinfo->polroles);
    4276             : 
    4277         498 :     if (polinfo->polqual != NULL)
    4278         430 :         appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
    4279             : 
    4280         498 :     if (polinfo->polwithcheck != NULL)
    4281         234 :         appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
    4282             : 
    4283         498 :     appendPQExpBufferStr(query, ";\n");
    4284             : 
    4285         498 :     appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
    4286         498 :     appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
    4287             : 
    4288         498 :     appendPQExpBuffer(polprefix, "POLICY %s ON",
    4289         498 :                       fmtId(polinfo->polname));
    4290             : 
    4291         498 :     tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
    4292             : 
    4293         498 :     if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4294         498 :         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
    4295         498 :                      ARCHIVE_OPTS(.tag = tag,
    4296             :                                   .namespace = polinfo->dobj.namespace->dobj.name,
    4297             :                                   .owner = tbinfo->rolname,
    4298             :                                   .description = "POLICY",
    4299             :                                   .section = SECTION_POST_DATA,
    4300             :                                   .createStmt = query->data,
    4301             :                                   .dropStmt = delqry->data));
    4302             : 
    4303         498 :     if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4304           0 :         dumpComment(fout, polprefix->data, qtabname,
    4305           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
    4306             :                     polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
    4307             : 
    4308         498 :     free(tag);
    4309         498 :     destroyPQExpBuffer(query);
    4310         498 :     destroyPQExpBuffer(delqry);
    4311         498 :     destroyPQExpBuffer(polprefix);
    4312         498 :     free(qtabname);
    4313             : }
    4314             : 
    4315             : /*
    4316             :  * getPublications
    4317             :  *    get information about publications
    4318             :  */
    4319             : void
    4320         320 : getPublications(Archive *fout)
    4321             : {
    4322         320 :     DumpOptions *dopt = fout->dopt;
    4323             :     PQExpBuffer query;
    4324             :     PGresult   *res;
    4325             :     PublicationInfo *pubinfo;
    4326             :     int         i_tableoid;
    4327             :     int         i_oid;
    4328             :     int         i_pubname;
    4329             :     int         i_pubowner;
    4330             :     int         i_puballtables;
    4331             :     int         i_pubinsert;
    4332             :     int         i_pubupdate;
    4333             :     int         i_pubdelete;
    4334             :     int         i_pubtruncate;
    4335             :     int         i_pubviaroot;
    4336             :     int         i_pubgencols;
    4337             :     int         i,
    4338             :                 ntups;
    4339             : 
    4340         320 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4341           0 :         return;
    4342             : 
    4343         320 :     query = createPQExpBuffer();
    4344             : 
    4345             :     /* Get the publications. */
    4346         320 :     appendPQExpBufferStr(query, "SELECT p.tableoid, p.oid, p.pubname, "
    4347             :                          "p.pubowner, p.puballtables, p.pubinsert, "
    4348             :                          "p.pubupdate, p.pubdelete, ");
    4349             : 
    4350         320 :     if (fout->remoteVersion >= 110000)
    4351         320 :         appendPQExpBufferStr(query, "p.pubtruncate, ");
    4352             :     else
    4353           0 :         appendPQExpBufferStr(query, "false AS pubtruncate, ");
    4354             : 
    4355         320 :     if (fout->remoteVersion >= 130000)
    4356         320 :         appendPQExpBufferStr(query, "p.pubviaroot, ");
    4357             :     else
    4358           0 :         appendPQExpBufferStr(query, "false AS pubviaroot, ");
    4359             : 
    4360         320 :     if (fout->remoteVersion >= 180000)
    4361         320 :         appendPQExpBufferStr(query, "p.pubgencols ");
    4362             :     else
    4363           0 :         appendPQExpBuffer(query, "'%c' AS pubgencols ", PUBLISH_GENCOLS_NONE);
    4364             : 
    4365         320 :     appendPQExpBufferStr(query, "FROM pg_publication p");
    4366             : 
    4367         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4368             : 
    4369         320 :     ntups = PQntuples(res);
    4370             : 
    4371         320 :     if (ntups == 0)
    4372         224 :         goto cleanup;
    4373             : 
    4374          96 :     i_tableoid = PQfnumber(res, "tableoid");
    4375          96 :     i_oid = PQfnumber(res, "oid");
    4376          96 :     i_pubname = PQfnumber(res, "pubname");
    4377          96 :     i_pubowner = PQfnumber(res, "pubowner");
    4378          96 :     i_puballtables = PQfnumber(res, "puballtables");
    4379          96 :     i_pubinsert = PQfnumber(res, "pubinsert");
    4380          96 :     i_pubupdate = PQfnumber(res, "pubupdate");
    4381          96 :     i_pubdelete = PQfnumber(res, "pubdelete");
    4382          96 :     i_pubtruncate = PQfnumber(res, "pubtruncate");
    4383          96 :     i_pubviaroot = PQfnumber(res, "pubviaroot");
    4384          96 :     i_pubgencols = PQfnumber(res, "pubgencols");
    4385             : 
    4386          96 :     pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
    4387             : 
    4388         568 :     for (i = 0; i < ntups; i++)
    4389             :     {
    4390         472 :         pubinfo[i].dobj.objType = DO_PUBLICATION;
    4391         472 :         pubinfo[i].dobj.catId.tableoid =
    4392         472 :             atooid(PQgetvalue(res, i, i_tableoid));
    4393         472 :         pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4394         472 :         AssignDumpId(&pubinfo[i].dobj);
    4395         472 :         pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
    4396         472 :         pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
    4397         472 :         pubinfo[i].puballtables =
    4398         472 :             (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
    4399         472 :         pubinfo[i].pubinsert =
    4400         472 :             (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
    4401         472 :         pubinfo[i].pubupdate =
    4402         472 :             (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
    4403         472 :         pubinfo[i].pubdelete =
    4404         472 :             (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
    4405         472 :         pubinfo[i].pubtruncate =
    4406         472 :             (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
    4407         472 :         pubinfo[i].pubviaroot =
    4408         472 :             (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
    4409         472 :         pubinfo[i].pubgencols_type =
    4410         472 :             *(PQgetvalue(res, i, i_pubgencols));
    4411             : 
    4412             :         /* Decide whether we want to dump it */
    4413         472 :         selectDumpableObject(&(pubinfo[i].dobj), fout);
    4414             :     }
    4415             : 
    4416          96 : cleanup:
    4417         320 :     PQclear(res);
    4418             : 
    4419         320 :     destroyPQExpBuffer(query);
    4420             : }
    4421             : 
    4422             : /*
    4423             :  * dumpPublication
    4424             :  *    dump the definition of the given publication
    4425             :  */
    4426             : static void
    4427         392 : dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
    4428             : {
    4429         392 :     DumpOptions *dopt = fout->dopt;
    4430             :     PQExpBuffer delq;
    4431             :     PQExpBuffer query;
    4432             :     char       *qpubname;
    4433         392 :     bool        first = true;
    4434             : 
    4435             :     /* Do nothing if not dumping schema */
    4436         392 :     if (!dopt->dumpSchema)
    4437          60 :         return;
    4438             : 
    4439         332 :     delq = createPQExpBuffer();
    4440         332 :     query = createPQExpBuffer();
    4441             : 
    4442         332 :     qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
    4443             : 
    4444         332 :     appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
    4445             :                       qpubname);
    4446             : 
    4447         332 :     appendPQExpBuffer(query, "CREATE PUBLICATION %s",
    4448             :                       qpubname);
    4449             : 
    4450         332 :     if (pubinfo->puballtables)
    4451          68 :         appendPQExpBufferStr(query, " FOR ALL TABLES");
    4452             : 
    4453         332 :     appendPQExpBufferStr(query, " WITH (publish = '");
    4454         332 :     if (pubinfo->pubinsert)
    4455             :     {
    4456         266 :         appendPQExpBufferStr(query, "insert");
    4457         266 :         first = false;
    4458             :     }
    4459             : 
    4460         332 :     if (pubinfo->pubupdate)
    4461             :     {
    4462         266 :         if (!first)
    4463         266 :             appendPQExpBufferStr(query, ", ");
    4464             : 
    4465         266 :         appendPQExpBufferStr(query, "update");
    4466         266 :         first = false;
    4467             :     }
    4468             : 
    4469         332 :     if (pubinfo->pubdelete)
    4470             :     {
    4471         266 :         if (!first)
    4472         266 :             appendPQExpBufferStr(query, ", ");
    4473             : 
    4474         266 :         appendPQExpBufferStr(query, "delete");
    4475         266 :         first = false;
    4476             :     }
    4477             : 
    4478         332 :     if (pubinfo->pubtruncate)
    4479             :     {
    4480         266 :         if (!first)
    4481         266 :             appendPQExpBufferStr(query, ", ");
    4482             : 
    4483         266 :         appendPQExpBufferStr(query, "truncate");
    4484         266 :         first = false;
    4485             :     }
    4486             : 
    4487         332 :     appendPQExpBufferChar(query, '\'');
    4488             : 
    4489         332 :     if (pubinfo->pubviaroot)
    4490           0 :         appendPQExpBufferStr(query, ", publish_via_partition_root = true");
    4491             : 
    4492         332 :     if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED)
    4493          66 :         appendPQExpBufferStr(query, ", publish_generated_columns = stored");
    4494             : 
    4495         332 :     appendPQExpBufferStr(query, ");\n");
    4496             : 
    4497         332 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4498         332 :         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
    4499         332 :                      ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
    4500             :                                   .owner = pubinfo->rolname,
    4501             :                                   .description = "PUBLICATION",
    4502             :                                   .section = SECTION_POST_DATA,
    4503             :                                   .createStmt = query->data,
    4504             :                                   .dropStmt = delq->data));
    4505             : 
    4506         332 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    4507          66 :         dumpComment(fout, "PUBLICATION", qpubname,
    4508             :                     NULL, pubinfo->rolname,
    4509             :                     pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4510             : 
    4511         332 :     if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    4512           0 :         dumpSecLabel(fout, "PUBLICATION", qpubname,
    4513             :                      NULL, pubinfo->rolname,
    4514             :                      pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
    4515             : 
    4516         332 :     destroyPQExpBuffer(delq);
    4517         332 :     destroyPQExpBuffer(query);
    4518         332 :     free(qpubname);
    4519             : }
    4520             : 
    4521             : /*
    4522             :  * getPublicationNamespaces
    4523             :  *    get information about publication membership for dumpable schemas.
    4524             :  */
    4525             : void
    4526         320 : getPublicationNamespaces(Archive *fout)
    4527             : {
    4528             :     PQExpBuffer query;
    4529             :     PGresult   *res;
    4530             :     PublicationSchemaInfo *pubsinfo;
    4531         320 :     DumpOptions *dopt = fout->dopt;
    4532             :     int         i_tableoid;
    4533             :     int         i_oid;
    4534             :     int         i_pnpubid;
    4535             :     int         i_pnnspid;
    4536             :     int         i,
    4537             :                 j,
    4538             :                 ntups;
    4539             : 
    4540         320 :     if (dopt->no_publications || fout->remoteVersion < 150000)
    4541           0 :         return;
    4542             : 
    4543         320 :     query = createPQExpBuffer();
    4544             : 
    4545             :     /* Collect all publication membership info. */
    4546         320 :     appendPQExpBufferStr(query,
    4547             :                          "SELECT tableoid, oid, pnpubid, pnnspid "
    4548             :                          "FROM pg_catalog.pg_publication_namespace");
    4549         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4550             : 
    4551         320 :     ntups = PQntuples(res);
    4552             : 
    4553         320 :     i_tableoid = PQfnumber(res, "tableoid");
    4554         320 :     i_oid = PQfnumber(res, "oid");
    4555         320 :     i_pnpubid = PQfnumber(res, "pnpubid");
    4556         320 :     i_pnnspid = PQfnumber(res, "pnnspid");
    4557             : 
    4558             :     /* this allocation may be more than we need */
    4559         320 :     pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
    4560         320 :     j = 0;
    4561             : 
    4562         508 :     for (i = 0; i < ntups; i++)
    4563             :     {
    4564         188 :         Oid         pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
    4565         188 :         Oid         pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
    4566             :         PublicationInfo *pubinfo;
    4567             :         NamespaceInfo *nspinfo;
    4568             : 
    4569             :         /*
    4570             :          * Ignore any entries for which we aren't interested in either the
    4571             :          * publication or the rel.
    4572             :          */
    4573         188 :         pubinfo = findPublicationByOid(pnpubid);
    4574         188 :         if (pubinfo == NULL)
    4575           0 :             continue;
    4576         188 :         nspinfo = findNamespaceByOid(pnnspid);
    4577         188 :         if (nspinfo == NULL)
    4578           0 :             continue;
    4579             : 
    4580             :         /* OK, make a DumpableObject for this relationship */
    4581         188 :         pubsinfo[j].dobj.objType = DO_PUBLICATION_TABLE_IN_SCHEMA;
    4582         188 :         pubsinfo[j].dobj.catId.tableoid =
    4583         188 :             atooid(PQgetvalue(res, i, i_tableoid));
    4584         188 :         pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4585         188 :         AssignDumpId(&pubsinfo[j].dobj);
    4586         188 :         pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
    4587         188 :         pubsinfo[j].dobj.name = nspinfo->dobj.name;
    4588         188 :         pubsinfo[j].publication = pubinfo;
    4589         188 :         pubsinfo[j].pubschema = nspinfo;
    4590             : 
    4591             :         /* Decide whether we want to dump it */
    4592         188 :         selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
    4593             : 
    4594         188 :         j++;
    4595             :     }
    4596             : 
    4597         320 :     PQclear(res);
    4598         320 :     destroyPQExpBuffer(query);
    4599             : }
    4600             : 
    4601             : /*
    4602             :  * getPublicationTables
    4603             :  *    get information about publication membership for dumpable tables.
    4604             :  */
    4605             : void
    4606         320 : getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
    4607             : {
    4608             :     PQExpBuffer query;
    4609             :     PGresult   *res;
    4610             :     PublicationRelInfo *pubrinfo;
    4611         320 :     DumpOptions *dopt = fout->dopt;
    4612             :     int         i_tableoid;
    4613             :     int         i_oid;
    4614             :     int         i_prpubid;
    4615             :     int         i_prrelid;
    4616             :     int         i_prrelqual;
    4617             :     int         i_prattrs;
    4618             :     int         i,
    4619             :                 j,
    4620             :                 ntups;
    4621             : 
    4622         320 :     if (dopt->no_publications || fout->remoteVersion < 100000)
    4623           0 :         return;
    4624             : 
    4625         320 :     query = createPQExpBuffer();
    4626             : 
    4627             :     /* Collect all publication membership info. */
    4628         320 :     if (fout->remoteVersion >= 150000)
    4629         320 :         appendPQExpBufferStr(query,
    4630             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4631             :                              "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
    4632             :                              "(CASE\n"
    4633             :                              "  WHEN pr.prattrs IS NOT NULL THEN\n"
    4634             :                              "    (SELECT array_agg(attname)\n"
    4635             :                              "       FROM\n"
    4636             :                              "         pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
    4637             :                              "         pg_catalog.pg_attribute\n"
    4638             :                              "      WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
    4639             :                              "  ELSE NULL END) prattrs "
    4640             :                              "FROM pg_catalog.pg_publication_rel pr");
    4641             :     else
    4642           0 :         appendPQExpBufferStr(query,
    4643             :                              "SELECT tableoid, oid, prpubid, prrelid, "
    4644             :                              "NULL AS prrelqual, NULL AS prattrs "
    4645             :                              "FROM pg_catalog.pg_publication_rel");
    4646         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4647             : 
    4648         320 :     ntups = PQntuples(res);
    4649             : 
    4650         320 :     i_tableoid = PQfnumber(res, "tableoid");
    4651         320 :     i_oid = PQfnumber(res, "oid");
    4652         320 :     i_prpubid = PQfnumber(res, "prpubid");
    4653         320 :     i_prrelid = PQfnumber(res, "prrelid");
    4654         320 :     i_prrelqual = PQfnumber(res, "prrelqual");
    4655         320 :     i_prattrs = PQfnumber(res, "prattrs");
    4656             : 
    4657             :     /* this allocation may be more than we need */
    4658         320 :     pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
    4659         320 :     j = 0;
    4660             : 
    4661         978 :     for (i = 0; i < ntups; i++)
    4662             :     {
    4663         658 :         Oid         prpubid = atooid(PQgetvalue(res, i, i_prpubid));
    4664         658 :         Oid         prrelid = atooid(PQgetvalue(res, i, i_prrelid));
    4665             :         PublicationInfo *pubinfo;
    4666             :         TableInfo  *tbinfo;
    4667             : 
    4668             :         /*
    4669             :          * Ignore any entries for which we aren't interested in either the
    4670             :          * publication or the rel.
    4671             :          */
    4672         658 :         pubinfo = findPublicationByOid(prpubid);
    4673         658 :         if (pubinfo == NULL)
    4674           0 :             continue;
    4675         658 :         tbinfo = findTableByOid(prrelid);
    4676         658 :         if (tbinfo == NULL)
    4677           0 :             continue;
    4678             : 
    4679             :         /* OK, make a DumpableObject for this relationship */
    4680         658 :         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
    4681         658 :         pubrinfo[j].dobj.catId.tableoid =
    4682         658 :             atooid(PQgetvalue(res, i, i_tableoid));
    4683         658 :         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    4684         658 :         AssignDumpId(&pubrinfo[j].dobj);
    4685         658 :         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    4686         658 :         pubrinfo[j].dobj.name = tbinfo->dobj.name;
    4687         658 :         pubrinfo[j].publication = pubinfo;
    4688         658 :         pubrinfo[j].pubtable = tbinfo;
    4689         658 :         if (PQgetisnull(res, i, i_prrelqual))
    4690         376 :             pubrinfo[j].pubrelqual = NULL;
    4691             :         else
    4692         282 :             pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
    4693             : 
    4694         658 :         if (!PQgetisnull(res, i, i_prattrs))
    4695             :         {
    4696             :             char      **attnames;
    4697             :             int         nattnames;
    4698             :             PQExpBuffer attribs;
    4699             : 
    4700         188 :             if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
    4701             :                               &attnames, &nattnames))
    4702           0 :                 pg_fatal("could not parse %s array", "prattrs");
    4703         188 :             attribs = createPQExpBuffer();
    4704         564 :             for (int k = 0; k < nattnames; k++)
    4705             :             {
    4706         376 :                 if (k > 0)
    4707         188 :                     appendPQExpBufferStr(attribs, ", ");
    4708             : 
    4709         376 :                 appendPQExpBufferStr(attribs, fmtId(attnames[k]));
    4710             :             }
    4711         188 :             pubrinfo[j].pubrattrs = attribs->data;
    4712         188 :             free(attribs);      /* but not attribs->data */
    4713         188 :             free(attnames);
    4714             :         }
    4715             :         else
    4716         470 :             pubrinfo[j].pubrattrs = NULL;
    4717             : 
    4718             :         /* Decide whether we want to dump it */
    4719         658 :         selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
    4720             : 
    4721         658 :         j++;
    4722             :     }
    4723             : 
    4724         320 :     PQclear(res);
    4725         320 :     destroyPQExpBuffer(query);
    4726             : }
    4727             : 
    4728             : /*
    4729             :  * dumpPublicationNamespace
    4730             :  *    dump the definition of the given publication schema mapping.
    4731             :  */
    4732             : static void
    4733         156 : dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
    4734             : {
    4735         156 :     DumpOptions *dopt = fout->dopt;
    4736         156 :     NamespaceInfo *schemainfo = pubsinfo->pubschema;
    4737         156 :     PublicationInfo *pubinfo = pubsinfo->publication;
    4738             :     PQExpBuffer query;
    4739             :     char       *tag;
    4740             : 
    4741             :     /* Do nothing if not dumping schema */
    4742         156 :     if (!dopt->dumpSchema)
    4743          24 :         return;
    4744             : 
    4745         132 :     tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
    4746             : 
    4747         132 :     query = createPQExpBuffer();
    4748             : 
    4749         132 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
    4750         132 :     appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
    4751             : 
    4752             :     /*
    4753             :      * There is no point in creating drop query as the drop is done by schema
    4754             :      * drop.
    4755             :      */
    4756         132 :     if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4757         132 :         ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
    4758         132 :                      ARCHIVE_OPTS(.tag = tag,
    4759             :                                   .namespace = schemainfo->dobj.name,
    4760             :                                   .owner = pubinfo->rolname,
    4761             :                                   .description = "PUBLICATION TABLES IN SCHEMA",
    4762             :                                   .section = SECTION_POST_DATA,
    4763             :                                   .createStmt = query->data));
    4764             : 
    4765             :     /* These objects can't currently have comments or seclabels */
    4766             : 
    4767         132 :     free(tag);
    4768         132 :     destroyPQExpBuffer(query);
    4769             : }
    4770             : 
    4771             : /*
    4772             :  * dumpPublicationTable
    4773             :  *    dump the definition of the given publication table mapping
    4774             :  */
    4775             : static void
    4776         546 : dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
    4777             : {
    4778         546 :     DumpOptions *dopt = fout->dopt;
    4779         546 :     PublicationInfo *pubinfo = pubrinfo->publication;
    4780         546 :     TableInfo  *tbinfo = pubrinfo->pubtable;
    4781             :     PQExpBuffer query;
    4782             :     char       *tag;
    4783             : 
    4784             :     /* Do nothing if not dumping schema */
    4785         546 :     if (!dopt->dumpSchema)
    4786          84 :         return;
    4787             : 
    4788         462 :     tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
    4789             : 
    4790         462 :     query = createPQExpBuffer();
    4791             : 
    4792         462 :     appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
    4793         462 :                       fmtId(pubinfo->dobj.name));
    4794         462 :     appendPQExpBuffer(query, " %s",
    4795         462 :                       fmtQualifiedDumpable(tbinfo));
    4796             : 
    4797         462 :     if (pubrinfo->pubrattrs)
    4798         132 :         appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
    4799             : 
    4800         462 :     if (pubrinfo->pubrelqual)
    4801             :     {
    4802             :         /*
    4803             :          * It's necessary to add parentheses around the expression because
    4804             :          * pg_get_expr won't supply the parentheses for things like WHERE
    4805             :          * TRUE.
    4806             :          */
    4807         198 :         appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
    4808             :     }
    4809         462 :     appendPQExpBufferStr(query, ";\n");
    4810             : 
    4811             :     /*
    4812             :      * There is no point in creating a drop query as the drop is done by table
    4813             :      * drop.  (If you think to change this, see also _printTocEntry().)
    4814             :      * Although this object doesn't really have ownership as such, set the
    4815             :      * owner field anyway to ensure that the command is run by the correct
    4816             :      * role at restore time.
    4817             :      */
    4818         462 :     if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    4819         462 :         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
    4820         462 :                      ARCHIVE_OPTS(.tag = tag,
    4821             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
    4822             :                                   .owner = pubinfo->rolname,
    4823             :                                   .description = "PUBLICATION TABLE",
    4824             :                                   .section = SECTION_POST_DATA,
    4825             :                                   .createStmt = query->data));
    4826             : 
    4827             :     /* These objects can't currently have comments or seclabels */
    4828             : 
    4829         462 :     free(tag);
    4830         462 :     destroyPQExpBuffer(query);
    4831             : }
    4832             : 
    4833             : /*
    4834             :  * Is the currently connected user a superuser?
    4835             :  */
    4836             : static bool
    4837         320 : is_superuser(Archive *fout)
    4838             : {
    4839         320 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
    4840             :     const char *val;
    4841             : 
    4842         320 :     val = PQparameterStatus(AH->connection, "is_superuser");
    4843             : 
    4844         320 :     if (val && strcmp(val, "on") == 0)
    4845         314 :         return true;
    4846             : 
    4847           6 :     return false;
    4848             : }
    4849             : 
    4850             : /*
    4851             :  * Set the given value to restrict_nonsystem_relation_kind value. Since
    4852             :  * restrict_nonsystem_relation_kind is introduced in minor version releases,
    4853             :  * the setting query is effective only where available.
    4854             :  */
    4855             : static void
    4856         388 : set_restrict_relation_kind(Archive *AH, const char *value)
    4857             : {
    4858         388 :     PQExpBuffer query = createPQExpBuffer();
    4859             :     PGresult   *res;
    4860             : 
    4861         388 :     appendPQExpBuffer(query,
    4862             :                       "SELECT set_config(name, '%s', false) "
    4863             :                       "FROM pg_settings "
    4864             :                       "WHERE name = 'restrict_nonsystem_relation_kind'",
    4865             :                       value);
    4866         388 :     res = ExecuteSqlQuery(AH, query->data, PGRES_TUPLES_OK);
    4867             : 
    4868         388 :     PQclear(res);
    4869         388 :     destroyPQExpBuffer(query);
    4870         388 : }
    4871             : 
    4872             : /*
    4873             :  * getSubscriptions
    4874             :  *    get information about subscriptions
    4875             :  */
    4876             : void
    4877         320 : getSubscriptions(Archive *fout)
    4878             : {
    4879         320 :     DumpOptions *dopt = fout->dopt;
    4880             :     PQExpBuffer query;
    4881             :     PGresult   *res;
    4882             :     SubscriptionInfo *subinfo;
    4883             :     int         i_tableoid;
    4884             :     int         i_oid;
    4885             :     int         i_subname;
    4886             :     int         i_subowner;
    4887             :     int         i_subbinary;
    4888             :     int         i_substream;
    4889             :     int         i_subtwophasestate;
    4890             :     int         i_subdisableonerr;
    4891             :     int         i_subpasswordrequired;
    4892             :     int         i_subrunasowner;
    4893             :     int         i_subconninfo;
    4894             :     int         i_subslotname;
    4895             :     int         i_subsynccommit;
    4896             :     int         i_subpublications;
    4897             :     int         i_suborigin;
    4898             :     int         i_suboriginremotelsn;
    4899             :     int         i_subenabled;
    4900             :     int         i_subfailover;
    4901             :     int         i,
    4902             :                 ntups;
    4903             : 
    4904         320 :     if (dopt->no_subscriptions || fout->remoteVersion < 100000)
    4905           0 :         return;
    4906             : 
    4907         320 :     if (!is_superuser(fout))
    4908             :     {
    4909             :         int         n;
    4910             : 
    4911           6 :         res = ExecuteSqlQuery(fout,
    4912             :                               "SELECT count(*) FROM pg_subscription "
    4913             :                               "WHERE subdbid = (SELECT oid FROM pg_database"
    4914             :                               "                 WHERE datname = current_database())",
    4915             :                               PGRES_TUPLES_OK);
    4916           6 :         n = atoi(PQgetvalue(res, 0, 0));
    4917           6 :         if (n > 0)
    4918           4 :             pg_log_warning("subscriptions not dumped because current user is not a superuser");
    4919           6 :         PQclear(res);
    4920           6 :         return;
    4921             :     }
    4922             : 
    4923         314 :     query = createPQExpBuffer();
    4924             : 
    4925             :     /* Get the subscriptions in current database. */
    4926         314 :     appendPQExpBufferStr(query,
    4927             :                          "SELECT s.tableoid, s.oid, s.subname,\n"
    4928             :                          " s.subowner,\n"
    4929             :                          " s.subconninfo, s.subslotname, s.subsynccommit,\n"
    4930             :                          " s.subpublications,\n");
    4931             : 
    4932         314 :     if (fout->remoteVersion >= 140000)
    4933         314 :         appendPQExpBufferStr(query, " s.subbinary,\n");
    4934             :     else
    4935           0 :         appendPQExpBufferStr(query, " false AS subbinary,\n");
    4936             : 
    4937         314 :     if (fout->remoteVersion >= 140000)
    4938         314 :         appendPQExpBufferStr(query, " s.substream,\n");
    4939             :     else
    4940           0 :         appendPQExpBufferStr(query, " 'f' AS substream,\n");
    4941             : 
    4942         314 :     if (fout->remoteVersion >= 150000)
    4943         314 :         appendPQExpBufferStr(query,
    4944             :                              " s.subtwophasestate,\n"
    4945             :                              " s.subdisableonerr,\n");
    4946             :     else
    4947           0 :         appendPQExpBuffer(query,
    4948             :                           " '%c' AS subtwophasestate,\n"
    4949             :                           " false AS subdisableonerr,\n",
    4950             :                           LOGICALREP_TWOPHASE_STATE_DISABLED);
    4951             : 
    4952         314 :     if (fout->remoteVersion >= 160000)
    4953         314 :         appendPQExpBufferStr(query,
    4954             :                              " s.subpasswordrequired,\n"
    4955             :                              " s.subrunasowner,\n"
    4956             :                              " s.suborigin,\n");
    4957             :     else
    4958           0 :         appendPQExpBuffer(query,
    4959             :                           " 't' AS subpasswordrequired,\n"
    4960             :                           " 't' AS subrunasowner,\n"
    4961             :                           " '%s' AS suborigin,\n",
    4962             :                           LOGICALREP_ORIGIN_ANY);
    4963             : 
    4964         314 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    4965          32 :         appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
    4966             :                              " s.subenabled,\n");
    4967             :     else
    4968         282 :         appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
    4969             :                              " false AS subenabled,\n");
    4970             : 
    4971         314 :     if (fout->remoteVersion >= 170000)
    4972         314 :         appendPQExpBufferStr(query,
    4973             :                              " s.subfailover\n");
    4974             :     else
    4975           0 :         appendPQExpBuffer(query,
    4976             :                           " false AS subfailover\n");
    4977             : 
    4978         314 :     appendPQExpBufferStr(query,
    4979             :                          "FROM pg_subscription s\n");
    4980             : 
    4981         314 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    4982          32 :         appendPQExpBufferStr(query,
    4983             :                              "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
    4984             :                              "    ON o.external_id = 'pg_' || s.oid::text \n");
    4985             : 
    4986         314 :     appendPQExpBufferStr(query,
    4987             :                          "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
    4988             :                          "                   WHERE datname = current_database())");
    4989             : 
    4990         314 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    4991             : 
    4992         314 :     ntups = PQntuples(res);
    4993             : 
    4994             :     /*
    4995             :      * Get subscription fields. We don't include subskiplsn in the dump as
    4996             :      * after restoring the dump this value may no longer be relevant.
    4997             :      */
    4998         314 :     i_tableoid = PQfnumber(res, "tableoid");
    4999         314 :     i_oid = PQfnumber(res, "oid");
    5000         314 :     i_subname = PQfnumber(res, "subname");
    5001         314 :     i_subowner = PQfnumber(res, "subowner");
    5002         314 :     i_subenabled = PQfnumber(res, "subenabled");
    5003         314 :     i_subbinary = PQfnumber(res, "subbinary");
    5004         314 :     i_substream = PQfnumber(res, "substream");
    5005         314 :     i_subtwophasestate = PQfnumber(res, "subtwophasestate");
    5006         314 :     i_subdisableonerr = PQfnumber(res, "subdisableonerr");
    5007         314 :     i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
    5008         314 :     i_subrunasowner = PQfnumber(res, "subrunasowner");
    5009         314 :     i_subfailover = PQfnumber(res, "subfailover");
    5010         314 :     i_subconninfo = PQfnumber(res, "subconninfo");
    5011         314 :     i_subslotname = PQfnumber(res, "subslotname");
    5012         314 :     i_subsynccommit = PQfnumber(res, "subsynccommit");
    5013         314 :     i_subpublications = PQfnumber(res, "subpublications");
    5014         314 :     i_suborigin = PQfnumber(res, "suborigin");
    5015         314 :     i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
    5016             : 
    5017         314 :     subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
    5018             : 
    5019         588 :     for (i = 0; i < ntups; i++)
    5020             :     {
    5021         274 :         subinfo[i].dobj.objType = DO_SUBSCRIPTION;
    5022         274 :         subinfo[i].dobj.catId.tableoid =
    5023         274 :             atooid(PQgetvalue(res, i, i_tableoid));
    5024         274 :         subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5025         274 :         AssignDumpId(&subinfo[i].dobj);
    5026         274 :         subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
    5027         274 :         subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
    5028             : 
    5029         274 :         subinfo[i].subenabled =
    5030         274 :             (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
    5031         274 :         subinfo[i].subbinary =
    5032         274 :             (strcmp(PQgetvalue(res, i, i_subbinary), "t") == 0);
    5033         274 :         subinfo[i].substream = *(PQgetvalue(res, i, i_substream));
    5034         274 :         subinfo[i].subtwophasestate = *(PQgetvalue(res, i, i_subtwophasestate));
    5035         274 :         subinfo[i].subdisableonerr =
    5036         274 :             (strcmp(PQgetvalue(res, i, i_subdisableonerr), "t") == 0);
    5037         274 :         subinfo[i].subpasswordrequired =
    5038         274 :             (strcmp(PQgetvalue(res, i, i_subpasswordrequired), "t") == 0);
    5039         274 :         subinfo[i].subrunasowner =
    5040         274 :             (strcmp(PQgetvalue(res, i, i_subrunasowner), "t") == 0);
    5041         274 :         subinfo[i].subfailover =
    5042         274 :             (strcmp(PQgetvalue(res, i, i_subfailover), "t") == 0);
    5043         548 :         subinfo[i].subconninfo =
    5044         274 :             pg_strdup(PQgetvalue(res, i, i_subconninfo));
    5045         274 :         if (PQgetisnull(res, i, i_subslotname))
    5046           0 :             subinfo[i].subslotname = NULL;
    5047             :         else
    5048         274 :             subinfo[i].subslotname =
    5049         274 :                 pg_strdup(PQgetvalue(res, i, i_subslotname));
    5050         548 :         subinfo[i].subsynccommit =
    5051         274 :             pg_strdup(PQgetvalue(res, i, i_subsynccommit));
    5052         548 :         subinfo[i].subpublications =
    5053         274 :             pg_strdup(PQgetvalue(res, i, i_subpublications));
    5054         274 :         subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
    5055         274 :         if (PQgetisnull(res, i, i_suboriginremotelsn))
    5056         272 :             subinfo[i].suboriginremotelsn = NULL;
    5057             :         else
    5058           2 :             subinfo[i].suboriginremotelsn =
    5059           2 :                 pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
    5060             : 
    5061             :         /* Decide whether we want to dump it */
    5062         274 :         selectDumpableObject(&(subinfo[i].dobj), fout);
    5063             :     }
    5064         314 :     PQclear(res);
    5065             : 
    5066         314 :     destroyPQExpBuffer(query);
    5067             : }
    5068             : 
    5069             : /*
    5070             :  * getSubscriptionTables
    5071             :  *    Get information about subscription membership for dumpable tables. This
    5072             :  *    will be used only in binary-upgrade mode for PG17 or later versions.
    5073             :  */
    5074             : void
    5075         320 : getSubscriptionTables(Archive *fout)
    5076             : {
    5077         320 :     DumpOptions *dopt = fout->dopt;
    5078         320 :     SubscriptionInfo *subinfo = NULL;
    5079             :     SubRelInfo *subrinfo;
    5080             :     PGresult   *res;
    5081             :     int         i_srsubid;
    5082             :     int         i_srrelid;
    5083             :     int         i_srsubstate;
    5084             :     int         i_srsublsn;
    5085             :     int         ntups;
    5086         320 :     Oid         last_srsubid = InvalidOid;
    5087             : 
    5088         320 :     if (dopt->no_subscriptions || !dopt->binary_upgrade ||
    5089          32 :         fout->remoteVersion < 170000)
    5090         288 :         return;
    5091             : 
    5092          32 :     res = ExecuteSqlQuery(fout,
    5093             :                           "SELECT srsubid, srrelid, srsubstate, srsublsn "
    5094             :                           "FROM pg_catalog.pg_subscription_rel "
    5095             :                           "ORDER BY srsubid",
    5096             :                           PGRES_TUPLES_OK);
    5097          32 :     ntups = PQntuples(res);
    5098          32 :     if (ntups == 0)
    5099          30 :         goto cleanup;
    5100             : 
    5101             :     /* Get pg_subscription_rel attributes */
    5102           2 :     i_srsubid = PQfnumber(res, "srsubid");
    5103           2 :     i_srrelid = PQfnumber(res, "srrelid");
    5104           2 :     i_srsubstate = PQfnumber(res, "srsubstate");
    5105           2 :     i_srsublsn = PQfnumber(res, "srsublsn");
    5106             : 
    5107           2 :     subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
    5108           6 :     for (int i = 0; i < ntups; i++)
    5109             :     {
    5110           4 :         Oid         cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
    5111           4 :         Oid         relid = atooid(PQgetvalue(res, i, i_srrelid));
    5112             :         TableInfo  *tblinfo;
    5113             : 
    5114             :         /*
    5115             :          * If we switched to a new subscription, check if the subscription
    5116             :          * exists.
    5117             :          */
    5118           4 :         if (cur_srsubid != last_srsubid)
    5119             :         {
    5120           4 :             subinfo = findSubscriptionByOid(cur_srsubid);
    5121           4 :             if (subinfo == NULL)
    5122           0 :                 pg_fatal("subscription with OID %u does not exist", cur_srsubid);
    5123             : 
    5124           4 :             last_srsubid = cur_srsubid;
    5125             :         }
    5126             : 
    5127           4 :         tblinfo = findTableByOid(relid);
    5128           4 :         if (tblinfo == NULL)
    5129           0 :             pg_fatal("failed sanity check, table with OID %u not found",
    5130             :                      relid);
    5131             : 
    5132             :         /* OK, make a DumpableObject for this relationship */
    5133           4 :         subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
    5134           4 :         subrinfo[i].dobj.catId.tableoid = relid;
    5135           4 :         subrinfo[i].dobj.catId.oid = cur_srsubid;
    5136           4 :         AssignDumpId(&subrinfo[i].dobj);
    5137           4 :         subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
    5138           4 :         subrinfo[i].tblinfo = tblinfo;
    5139           4 :         subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
    5140           4 :         if (PQgetisnull(res, i, i_srsublsn))
    5141           2 :             subrinfo[i].srsublsn = NULL;
    5142             :         else
    5143           2 :             subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
    5144             : 
    5145           4 :         subrinfo[i].subinfo = subinfo;
    5146             : 
    5147             :         /* Decide whether we want to dump it */
    5148           4 :         selectDumpableObject(&(subrinfo[i].dobj), fout);
    5149             :     }
    5150             : 
    5151           2 : cleanup:
    5152          32 :     PQclear(res);
    5153             : }
    5154             : 
    5155             : /*
    5156             :  * dumpSubscriptionTable
    5157             :  *    Dump the definition of the given subscription table mapping. This will be
    5158             :  *    used only in binary-upgrade mode for PG17 or later versions.
    5159             :  */
    5160             : static void
    5161           4 : dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
    5162             : {
    5163           4 :     DumpOptions *dopt = fout->dopt;
    5164           4 :     SubscriptionInfo *subinfo = subrinfo->subinfo;
    5165             :     PQExpBuffer query;
    5166             :     char       *tag;
    5167             : 
    5168             :     /* Do nothing if not dumping schema */
    5169           4 :     if (!dopt->dumpSchema)
    5170           0 :         return;
    5171             : 
    5172             :     Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
    5173             : 
    5174           4 :     tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
    5175             : 
    5176           4 :     query = createPQExpBuffer();
    5177             : 
    5178           4 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5179             :     {
    5180             :         /*
    5181             :          * binary_upgrade_add_sub_rel_state will add the subscription relation
    5182             :          * to pg_subscription_rel table. This will be used only in
    5183             :          * binary-upgrade mode.
    5184             :          */
    5185           4 :         appendPQExpBufferStr(query,
    5186             :                              "\n-- For binary upgrade, must preserve the subscriber table.\n");
    5187           4 :         appendPQExpBufferStr(query,
    5188             :                              "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
    5189           4 :         appendStringLiteralAH(query, subrinfo->dobj.name, fout);
    5190           4 :         appendPQExpBuffer(query,
    5191             :                           ", %u, '%c'",
    5192           4 :                           subrinfo->tblinfo->dobj.catId.oid,
    5193           4 :                           subrinfo->srsubstate);
    5194             : 
    5195           4 :         if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
    5196           2 :             appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
    5197             :         else
    5198           2 :             appendPQExpBuffer(query, ", NULL");
    5199             : 
    5200           4 :         appendPQExpBufferStr(query, ");\n");
    5201             :     }
    5202             : 
    5203             :     /*
    5204             :      * There is no point in creating a drop query as the drop is done by table
    5205             :      * drop.  (If you think to change this, see also _printTocEntry().)
    5206             :      * Although this object doesn't really have ownership as such, set the
    5207             :      * owner field anyway to ensure that the command is run by the correct
    5208             :      * role at restore time.
    5209             :      */
    5210           4 :     if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5211           4 :         ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
    5212           4 :                      ARCHIVE_OPTS(.tag = tag,
    5213             :                                   .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
    5214             :                                   .owner = subinfo->rolname,
    5215             :                                   .description = "SUBSCRIPTION TABLE",
    5216             :                                   .section = SECTION_POST_DATA,
    5217             :                                   .createStmt = query->data));
    5218             : 
    5219             :     /* These objects can't currently have comments or seclabels */
    5220             : 
    5221           4 :     free(tag);
    5222           4 :     destroyPQExpBuffer(query);
    5223             : }
    5224             : 
    5225             : /*
    5226             :  * dumpSubscription
    5227             :  *    dump the definition of the given subscription
    5228             :  */
    5229             : static void
    5230         238 : dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
    5231             : {
    5232         238 :     DumpOptions *dopt = fout->dopt;
    5233             :     PQExpBuffer delq;
    5234             :     PQExpBuffer query;
    5235             :     PQExpBuffer publications;
    5236             :     char       *qsubname;
    5237         238 :     char      **pubnames = NULL;
    5238         238 :     int         npubnames = 0;
    5239             :     int         i;
    5240             : 
    5241             :     /* Do nothing if not dumping schema */
    5242         238 :     if (!dopt->dumpSchema)
    5243          36 :         return;
    5244             : 
    5245         202 :     delq = createPQExpBuffer();
    5246         202 :     query = createPQExpBuffer();
    5247             : 
    5248         202 :     qsubname = pg_strdup(fmtId(subinfo->dobj.name));
    5249             : 
    5250         202 :     appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
    5251             :                       qsubname);
    5252             : 
    5253         202 :     appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
    5254             :                       qsubname);
    5255         202 :     appendStringLiteralAH(query, subinfo->subconninfo, fout);
    5256             : 
    5257             :     /* Build list of quoted publications and append them to query. */
    5258         202 :     if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
    5259           0 :         pg_fatal("could not parse %s array", "subpublications");
    5260             : 
    5261         202 :     publications = createPQExpBuffer();
    5262         404 :     for (i = 0; i < npubnames; i++)
    5263             :     {
    5264         202 :         if (i > 0)
    5265           0 :             appendPQExpBufferStr(publications, ", ");
    5266             : 
    5267         202 :         appendPQExpBufferStr(publications, fmtId(pubnames[i]));
    5268             :     }
    5269             : 
    5270         202 :     appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
    5271         202 :     if (subinfo->subslotname)
    5272         202 :         appendStringLiteralAH(query, subinfo->subslotname, fout);
    5273             :     else
    5274           0 :         appendPQExpBufferStr(query, "NONE");
    5275             : 
    5276         202 :     if (subinfo->subbinary)
    5277           0 :         appendPQExpBufferStr(query, ", binary = true");
    5278             : 
    5279         202 :     if (subinfo->substream == LOGICALREP_STREAM_ON)
    5280          66 :         appendPQExpBufferStr(query, ", streaming = on");
    5281         136 :     else if (subinfo->substream == LOGICALREP_STREAM_PARALLEL)
    5282          70 :         appendPQExpBufferStr(query, ", streaming = parallel");
    5283             :     else
    5284          66 :         appendPQExpBufferStr(query, ", streaming = off");
    5285             : 
    5286         202 :     if (subinfo->subtwophasestate != LOGICALREP_TWOPHASE_STATE_DISABLED)
    5287           0 :         appendPQExpBufferStr(query, ", two_phase = on");
    5288             : 
    5289         202 :     if (subinfo->subdisableonerr)
    5290           0 :         appendPQExpBufferStr(query, ", disable_on_error = true");
    5291             : 
    5292         202 :     if (!subinfo->subpasswordrequired)
    5293           0 :         appendPQExpBuffer(query, ", password_required = false");
    5294             : 
    5295         202 :     if (subinfo->subrunasowner)
    5296           0 :         appendPQExpBufferStr(query, ", run_as_owner = true");
    5297             : 
    5298         202 :     if (subinfo->subfailover)
    5299           2 :         appendPQExpBufferStr(query, ", failover = true");
    5300             : 
    5301         202 :     if (strcmp(subinfo->subsynccommit, "off") != 0)
    5302           0 :         appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
    5303             : 
    5304         202 :     if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
    5305          66 :         appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
    5306             : 
    5307         202 :     appendPQExpBufferStr(query, ");\n");
    5308             : 
    5309             :     /*
    5310             :      * In binary-upgrade mode, we allow the replication to continue after the
    5311             :      * upgrade.
    5312             :      */
    5313         202 :     if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
    5314             :     {
    5315          10 :         if (subinfo->suboriginremotelsn)
    5316             :         {
    5317             :             /*
    5318             :              * Preserve the remote_lsn for the subscriber's replication
    5319             :              * origin. This value is required to start the replication from
    5320             :              * the position before the upgrade. This value will be stale if
    5321             :              * the publisher gets upgraded before the subscriber node.
    5322             :              * However, this shouldn't be a problem as the upgrade of the
    5323             :              * publisher ensures that all the transactions were replicated
    5324             :              * before upgrading it.
    5325             :              */
    5326           2 :             appendPQExpBufferStr(query,
    5327             :                                  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
    5328           2 :             appendPQExpBufferStr(query,
    5329             :                                  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
    5330           2 :             appendStringLiteralAH(query, subinfo->dobj.name, fout);
    5331           2 :             appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
    5332             :         }
    5333             : 
    5334          10 :         if (subinfo->subenabled)
    5335             :         {
    5336             :             /*
    5337             :              * Enable the subscription to allow the replication to continue
    5338             :              * after the upgrade.
    5339             :              */
    5340           2 :             appendPQExpBufferStr(query,
    5341             :                                  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
    5342           2 :             appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
    5343             :         }
    5344             :     }
    5345             : 
    5346         202 :     if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
    5347         202 :         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
    5348         202 :                      ARCHIVE_OPTS(.tag = subinfo->dobj.name,
    5349             :                                   .owner = subinfo->rolname,
    5350             :                                   .description = "SUBSCRIPTION",
    5351             :                                   .section = SECTION_POST_DATA,
    5352             :                                   .createStmt = query->data,
    5353             :                                   .dropStmt = delq->data));
    5354             : 
    5355         202 :     if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
    5356          66 :         dumpComment(fout, "SUBSCRIPTION", qsubname,
    5357             :                     NULL, subinfo->rolname,
    5358             :                     subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5359             : 
    5360         202 :     if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
    5361           0 :         dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
    5362             :                      NULL, subinfo->rolname,
    5363             :                      subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
    5364             : 
    5365         202 :     destroyPQExpBuffer(publications);
    5366         202 :     free(pubnames);
    5367             : 
    5368         202 :     destroyPQExpBuffer(delq);
    5369         202 :     destroyPQExpBuffer(query);
    5370         202 :     free(qsubname);
    5371             : }
    5372             : 
    5373             : /*
    5374             :  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
    5375             :  * the object needs.
    5376             :  */
    5377             : static void
    5378       10286 : append_depends_on_extension(Archive *fout,
    5379             :                             PQExpBuffer create,
    5380             :                             const DumpableObject *dobj,
    5381             :                             const char *catalog,
    5382             :                             const char *keyword,
    5383             :                             const char *objname)
    5384             : {
    5385       10286 :     if (dobj->depends_on_ext)
    5386             :     {
    5387             :         char       *nm;
    5388             :         PGresult   *res;
    5389             :         PQExpBuffer query;
    5390             :         int         ntups;
    5391             :         int         i_extname;
    5392             :         int         i;
    5393             : 
    5394             :         /* dodge fmtId() non-reentrancy */
    5395          84 :         nm = pg_strdup(objname);
    5396             : 
    5397          84 :         query = createPQExpBuffer();
    5398          84 :         appendPQExpBuffer(query,
    5399             :                           "SELECT e.extname "
    5400             :                           "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
    5401             :                           "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
    5402             :                           "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
    5403             :                           "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
    5404             :                           catalog,
    5405             :                           dobj->catId.oid);
    5406          84 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5407          84 :         ntups = PQntuples(res);
    5408          84 :         i_extname = PQfnumber(res, "extname");
    5409         168 :         for (i = 0; i < ntups; i++)
    5410             :         {
    5411          84 :             appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
    5412             :                               keyword, nm,
    5413          84 :                               fmtId(PQgetvalue(res, i, i_extname)));
    5414             :         }
    5415             : 
    5416          84 :         PQclear(res);
    5417          84 :         destroyPQExpBuffer(query);
    5418          84 :         pg_free(nm);
    5419             :     }
    5420       10286 : }
    5421             : 
    5422             : static Oid
    5423           0 : get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
    5424             : {
    5425             :     /*
    5426             :      * If the old version didn't assign an array type, but the new version
    5427             :      * does, we must select an unused type OID to assign.  This currently only
    5428             :      * happens for domains, when upgrading pre-v11 to v11 and up.
    5429             :      *
    5430             :      * Note: local state here is kind of ugly, but we must have some, since we
    5431             :      * mustn't choose the same unused OID more than once.
    5432             :      */
    5433             :     static Oid  next_possible_free_oid = FirstNormalObjectId;
    5434             :     PGresult   *res;
    5435             :     bool        is_dup;
    5436             : 
    5437             :     do
    5438             :     {
    5439           0 :         ++next_possible_free_oid;
    5440           0 :         printfPQExpBuffer(upgrade_query,
    5441             :                           "SELECT EXISTS(SELECT 1 "
    5442             :                           "FROM pg_catalog.pg_type "
    5443             :                           "WHERE oid = '%u'::pg_catalog.oid);",
    5444             :                           next_possible_free_oid);
    5445           0 :         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5446           0 :         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
    5447           0 :         PQclear(res);
    5448           0 :     } while (is_dup);
    5449             : 
    5450           0 :     return next_possible_free_oid;
    5451             : }
    5452             : 
    5453             : static void
    5454        1762 : binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
    5455             :                                          PQExpBuffer upgrade_buffer,
    5456             :                                          Oid pg_type_oid,
    5457             :                                          bool force_array_type,
    5458             :                                          bool include_multirange_type)
    5459             : {
    5460        1762 :     PQExpBuffer upgrade_query = createPQExpBuffer();
    5461             :     PGresult   *res;
    5462             :     Oid         pg_type_array_oid;
    5463             :     Oid         pg_type_multirange_oid;
    5464             :     Oid         pg_type_multirange_array_oid;
    5465             :     TypeInfo   *tinfo;
    5466             : 
    5467        1762 :     appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
    5468        1762 :     appendPQExpBuffer(upgrade_buffer,
    5469             :                       "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5470             :                       pg_type_oid);
    5471             : 
    5472        1762 :     tinfo = findTypeByOid(pg_type_oid);
    5473        1762 :     if (tinfo)
    5474        1762 :         pg_type_array_oid = tinfo->typarray;
    5475             :     else
    5476           0 :         pg_type_array_oid = InvalidOid;
    5477             : 
    5478        1762 :     if (!OidIsValid(pg_type_array_oid) && force_array_type)
    5479           0 :         pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5480             : 
    5481        1762 :     if (OidIsValid(pg_type_array_oid))
    5482             :     {
    5483        1758 :         appendPQExpBufferStr(upgrade_buffer,
    5484             :                              "\n-- For binary upgrade, must preserve pg_type array oid\n");
    5485        1758 :         appendPQExpBuffer(upgrade_buffer,
    5486             :                           "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5487             :                           pg_type_array_oid);
    5488             :     }
    5489             : 
    5490             :     /*
    5491             :      * Pre-set the multirange type oid and its own array type oid.
    5492             :      */
    5493        1762 :     if (include_multirange_type)
    5494             :     {
    5495          16 :         if (fout->remoteVersion >= 140000)
    5496             :         {
    5497          16 :             printfPQExpBuffer(upgrade_query,
    5498             :                               "SELECT t.oid, t.typarray "
    5499             :                               "FROM pg_catalog.pg_type t "
    5500             :                               "JOIN pg_catalog.pg_range r "
    5501             :                               "ON t.oid = r.rngmultitypid "
    5502             :                               "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
    5503             :                               pg_type_oid);
    5504             : 
    5505          16 :             res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
    5506             : 
    5507          16 :             pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
    5508          16 :             pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
    5509             : 
    5510          16 :             PQclear(res);
    5511             :         }
    5512             :         else
    5513             :         {
    5514           0 :             pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5515           0 :             pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
    5516             :         }
    5517             : 
    5518          16 :         appendPQExpBufferStr(upgrade_buffer,
    5519             :                              "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
    5520          16 :         appendPQExpBuffer(upgrade_buffer,
    5521             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5522             :                           pg_type_multirange_oid);
    5523          16 :         appendPQExpBufferStr(upgrade_buffer,
    5524             :                              "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
    5525          16 :         appendPQExpBuffer(upgrade_buffer,
    5526             :                           "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
    5527             :                           pg_type_multirange_array_oid);
    5528             :     }
    5529             : 
    5530        1762 :     destroyPQExpBuffer(upgrade_query);
    5531        1762 : }
    5532             : 
    5533             : static void
    5534        1620 : binary_upgrade_set_type_oids_by_rel(Archive *fout,
    5535             :                                     PQExpBuffer upgrade_buffer,
    5536             :                                     const TableInfo *tbinfo)
    5537             : {
    5538        1620 :     Oid         pg_type_oid = tbinfo->reltype;
    5539             : 
    5540        1620 :     if (OidIsValid(pg_type_oid))
    5541        1620 :         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
    5542             :                                                  pg_type_oid, false, false);
    5543        1620 : }
    5544             : 
    5545             : /*
    5546             :  * bsearch() comparator for BinaryUpgradeClassOidItem
    5547             :  */
    5548             : static int
    5549       23476 : BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
    5550             : {
    5551       23476 :     BinaryUpgradeClassOidItem v1 = *((const BinaryUpgradeClassOidItem *) p1);
    5552       23476 :     BinaryUpgradeClassOidItem v2 = *((const BinaryUpgradeClassOidItem *) p2);
    5553             : 
    5554       23476 :     return pg_cmp_u32(v1.oid, v2.oid);
    5555             : }
    5556             : 
    5557             : /*
    5558             :  * collectBinaryUpgradeClassOids
    5559             :  *
    5560             :  * Construct a table of pg_class information required for
    5561             :  * binary_upgrade_set_pg_class_oids().  The table is sorted by OID for speed in
    5562             :  * lookup.
    5563             :  */
    5564             : static void
    5565          32 : collectBinaryUpgradeClassOids(Archive *fout)
    5566             : {
    5567             :     PGresult   *res;
    5568             :     const char *query;
    5569             : 
    5570          32 :     query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
    5571             :         "ct.relfilenode, i.indexrelid, cti.relfilenode "
    5572             :         "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
    5573             :         "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
    5574             :         "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
    5575             :         "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
    5576             :         "ORDER BY c.oid;";
    5577             : 
    5578          32 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
    5579             : 
    5580          32 :     nbinaryUpgradeClassOids = PQntuples(res);
    5581          32 :     binaryUpgradeClassOids = (BinaryUpgradeClassOidItem *)
    5582          32 :         pg_malloc(nbinaryUpgradeClassOids * sizeof(BinaryUpgradeClassOidItem));
    5583             : 
    5584       16790 :     for (int i = 0; i < nbinaryUpgradeClassOids; i++)
    5585             :     {
    5586       16758 :         binaryUpgradeClassOids[i].oid = atooid(PQgetvalue(res, i, 0));
    5587       16758 :         binaryUpgradeClassOids[i].relkind = *PQgetvalue(res, i, 1);
    5588       16758 :         binaryUpgradeClassOids[i].relfilenumber = atooid(PQgetvalue(res, i, 2));
    5589       16758 :         binaryUpgradeClassOids[i].toast_oid = atooid(PQgetvalue(res, i, 3));
    5590       16758 :         binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4));
    5591       16758 :         binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5));
    5592       16758 :         binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6));
    5593             :     }
    5594             : 
    5595          32 :     PQclear(res);
    5596          32 : }
    5597             : 
    5598             : static void
    5599        2374 : binary_upgrade_set_pg_class_oids(Archive *fout,
    5600             :                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
    5601             : {
    5602        2374 :     BinaryUpgradeClassOidItem key = {0};
    5603             :     BinaryUpgradeClassOidItem *entry;
    5604             : 
    5605             :     Assert(binaryUpgradeClassOids);
    5606             : 
    5607             :     /*
    5608             :      * Preserve the OID and relfilenumber of the table, table's index, table's
    5609             :      * toast table and toast table's index if any.
    5610             :      *
    5611             :      * One complexity is that the current table definition might not require
    5612             :      * the creation of a TOAST table, but the old database might have a TOAST
    5613             :      * table that was created earlier, before some wide columns were dropped.
    5614             :      * By setting the TOAST oid we force creation of the TOAST heap and index
    5615             :      * by the new backend, so we can copy the files during binary upgrade
    5616             :      * without worrying about this case.
    5617             :      */
    5618        2374 :     key.oid = pg_class_oid;
    5619        2374 :     entry = bsearch(&key, binaryUpgradeClassOids, nbinaryUpgradeClassOids,
    5620             :                     sizeof(BinaryUpgradeClassOidItem),
    5621             :                     BinaryUpgradeClassOidItemCmp);
    5622             : 
    5623        2374 :     appendPQExpBufferStr(upgrade_buffer,
    5624             :                          "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
    5625             : 
    5626        2374 :     if (entry->relkind != RELKIND_INDEX &&
    5627        1828 :         entry->relkind != RELKIND_PARTITIONED_INDEX)
    5628             :     {
    5629        1778 :         appendPQExpBuffer(upgrade_buffer,
    5630             :                           "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
    5631             :                           pg_class_oid);
    5632             : 
    5633             :         /*
    5634             :          * Not every relation has storage. Also, in a pre-v12 database,
    5635             :          * partitioned tables have a relfilenumber, which should not be
    5636             :          * preserved when upgrading.
    5637             :          */
    5638        1778 :         if (RelFileNumberIsValid(entry->relfilenumber) &&
    5639        1464 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5640        1464 :             appendPQExpBuffer(upgrade_buffer,
    5641             :                               "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
    5642             :                               entry->relfilenumber);
    5643             : 
    5644             :         /*
    5645             :          * In a pre-v12 database, partitioned tables might be marked as having
    5646             :          * toast tables, but we should ignore them if so.
    5647             :          */
    5648        1778 :         if (OidIsValid(entry->toast_oid) &&
    5649         552 :             entry->relkind != RELKIND_PARTITIONED_TABLE)
    5650             :         {
    5651         552 :             appendPQExpBuffer(upgrade_buffer,
    5652             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
    5653             :                               entry->toast_oid);
    5654         552 :             appendPQExpBuffer(upgrade_buffer,
    5655             :                               "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
    5656             :                               entry->toast_relfilenumber);
    5657             : 
    5658             :             /* every toast table has an index */
    5659         552 :             appendPQExpBuffer(upgrade_buffer,
    5660             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5661             :                               entry->toast_index_oid);
    5662         552 :             appendPQExpBuffer(upgrade_buffer,
    5663             :                               "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5664             :                               entry->toast_index_relfilenumber);
    5665             :         }
    5666             :     }
    5667             :     else
    5668             :     {
    5669             :         /* Preserve the OID and relfilenumber of the index */
    5670         596 :         appendPQExpBuffer(upgrade_buffer,
    5671             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
    5672             :                           pg_class_oid);
    5673         596 :         appendPQExpBuffer(upgrade_buffer,
    5674             :                           "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
    5675             :                           entry->relfilenumber);
    5676             :     }
    5677             : 
    5678        2374 :     appendPQExpBufferChar(upgrade_buffer, '\n');
    5679        2374 : }
    5680             : 
    5681             : /*
    5682             :  * If the DumpableObject is a member of an extension, add a suitable
    5683             :  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
    5684             :  *
    5685             :  * For somewhat historical reasons, objname should already be quoted,
    5686             :  * but not objnamespace (if any).
    5687             :  */
    5688             : static void
    5689        2782 : binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
    5690             :                                 const DumpableObject *dobj,
    5691             :                                 const char *objtype,
    5692             :                                 const char *objname,
    5693             :                                 const char *objnamespace)
    5694             : {
    5695        2782 :     DumpableObject *extobj = NULL;
    5696             :     int         i;
    5697             : 
    5698        2782 :     if (!dobj->ext_member)
    5699        2750 :         return;
    5700             : 
    5701             :     /*
    5702             :      * Find the parent extension.  We could avoid this search if we wanted to
    5703             :      * add a link field to DumpableObject, but the space costs of that would
    5704             :      * be considerable.  We assume that member objects could only have a
    5705             :      * direct dependency on their own extension, not any others.
    5706             :      */
    5707          32 :     for (i = 0; i < dobj->nDeps; i++)
    5708             :     {
    5709          32 :         extobj = findObjectByDumpId(dobj->dependencies[i]);
    5710          32 :         if (extobj && extobj->objType == DO_EXTENSION)
    5711          32 :             break;
    5712           0 :         extobj = NULL;
    5713             :     }
    5714          32 :     if (extobj == NULL)
    5715           0 :         pg_fatal("could not find parent extension for %s %s",
    5716             :                  objtype, objname);
    5717             : 
    5718          32 :     appendPQExpBufferStr(upgrade_buffer,
    5719             :                          "\n-- For binary upgrade, handle extension membership the hard way\n");
    5720          32 :     appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
    5721          32 :                       fmtId(extobj->name),
    5722             :                       objtype);
    5723          32 :     if (objnamespace && *objnamespace)
    5724          26 :         appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
    5725          32 :     appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
    5726             : }
    5727             : 
    5728             : /*
    5729             :  * getNamespaces:
    5730             :  *    get information about all namespaces in the system catalogs
    5731             :  */
    5732             : void
    5733         322 : getNamespaces(Archive *fout)
    5734             : {
    5735             :     PGresult   *res;
    5736             :     int         ntups;
    5737             :     int         i;
    5738             :     PQExpBuffer query;
    5739             :     NamespaceInfo *nsinfo;
    5740             :     int         i_tableoid;
    5741             :     int         i_oid;
    5742             :     int         i_nspname;
    5743             :     int         i_nspowner;
    5744             :     int         i_nspacl;
    5745             :     int         i_acldefault;
    5746             : 
    5747         322 :     query = createPQExpBuffer();
    5748             : 
    5749             :     /*
    5750             :      * we fetch all namespaces including system ones, so that every object we
    5751             :      * read in can be linked to a containing namespace.
    5752             :      */
    5753         322 :     appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
    5754             :                          "n.nspowner, "
    5755             :                          "n.nspacl, "
    5756             :                          "acldefault('n', n.nspowner) AS acldefault "
    5757             :                          "FROM pg_namespace n");
    5758             : 
    5759         322 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5760             : 
    5761         322 :     ntups = PQntuples(res);
    5762             : 
    5763         322 :     nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
    5764             : 
    5765         322 :     i_tableoid = PQfnumber(res, "tableoid");
    5766         322 :     i_oid = PQfnumber(res, "oid");
    5767         322 :     i_nspname = PQfnumber(res, "nspname");
    5768         322 :     i_nspowner = PQfnumber(res, "nspowner");
    5769         322 :     i_nspacl = PQfnumber(res, "nspacl");
    5770         322 :     i_acldefault = PQfnumber(res, "acldefault");
    5771             : 
    5772        2942 :     for (i = 0; i < ntups; i++)
    5773             :     {
    5774             :         const char *nspowner;
    5775             : 
    5776        2620 :         nsinfo[i].dobj.objType = DO_NAMESPACE;
    5777        2620 :         nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5778        2620 :         nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5779        2620 :         AssignDumpId(&nsinfo[i].dobj);
    5780        2620 :         nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
    5781        2620 :         nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
    5782        2620 :         nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    5783        2620 :         nsinfo[i].dacl.privtype = 0;
    5784        2620 :         nsinfo[i].dacl.initprivs = NULL;
    5785        2620 :         nspowner = PQgetvalue(res, i, i_nspowner);
    5786        2620 :         nsinfo[i].nspowner = atooid(nspowner);
    5787        2620 :         nsinfo[i].rolname = getRoleName(nspowner);
    5788             : 
    5789             :         /* Decide whether to dump this namespace */
    5790        2620 :         selectDumpableNamespace(&nsinfo[i], fout);
    5791             : 
    5792             :         /* Mark whether namespace has an ACL */
    5793        2620 :         if (!PQgetisnull(res, i, i_nspacl))
    5794        1094 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5795             : 
    5796             :         /*
    5797             :          * We ignore any pg_init_privs.initprivs entry for the public schema
    5798             :          * and assume a predetermined default, for several reasons.  First,
    5799             :          * dropping and recreating the schema removes its pg_init_privs entry,
    5800             :          * but an empty destination database starts with this ACL nonetheless.
    5801             :          * Second, we support dump/reload of public schema ownership changes.
    5802             :          * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
    5803             :          * initprivs continues to reflect the initial owner.  Hence,
    5804             :          * synthesize the value that nspacl will have after the restore's
    5805             :          * ALTER SCHEMA OWNER.  Third, this makes the destination database
    5806             :          * match the source's ACL, even if the latter was an initdb-default
    5807             :          * ACL, which changed in v15.  An upgrade pulls in changes to most
    5808             :          * system object ACLs that the DBA had not customized.  We've made the
    5809             :          * public schema depart from that, because changing its ACL so easily
    5810             :          * breaks applications.
    5811             :          */
    5812        2620 :         if (strcmp(nsinfo[i].dobj.name, "public") == 0)
    5813             :         {
    5814         314 :             PQExpBuffer aclarray = createPQExpBuffer();
    5815         314 :             PQExpBuffer aclitem = createPQExpBuffer();
    5816             : 
    5817             :             /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
    5818         314 :             appendPQExpBufferChar(aclarray, '{');
    5819         314 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5820         314 :             appendPQExpBufferStr(aclitem, "=UC/");
    5821         314 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5822         314 :             appendPGArray(aclarray, aclitem->data);
    5823         314 :             resetPQExpBuffer(aclitem);
    5824         314 :             appendPQExpBufferStr(aclitem, "=U/");
    5825         314 :             quoteAclUserName(aclitem, nsinfo[i].rolname);
    5826         314 :             appendPGArray(aclarray, aclitem->data);
    5827         314 :             appendPQExpBufferChar(aclarray, '}');
    5828             : 
    5829         314 :             nsinfo[i].dacl.privtype = 'i';
    5830         314 :             nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
    5831         314 :             nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    5832             : 
    5833         314 :             destroyPQExpBuffer(aclarray);
    5834         314 :             destroyPQExpBuffer(aclitem);
    5835             :         }
    5836             :     }
    5837             : 
    5838         322 :     PQclear(res);
    5839         322 :     destroyPQExpBuffer(query);
    5840         322 : }
    5841             : 
    5842             : /*
    5843             :  * findNamespace:
    5844             :  *      given a namespace OID, look up the info read by getNamespaces
    5845             :  */
    5846             : static NamespaceInfo *
    5847     1004126 : findNamespace(Oid nsoid)
    5848             : {
    5849             :     NamespaceInfo *nsinfo;
    5850             : 
    5851     1004126 :     nsinfo = findNamespaceByOid(nsoid);
    5852     1004126 :     if (nsinfo == NULL)
    5853           0 :         pg_fatal("schema with OID %u does not exist", nsoid);
    5854     1004126 :     return nsinfo;
    5855             : }
    5856             : 
    5857             : /*
    5858             :  * getExtensions:
    5859             :  *    read all extensions in the system catalogs and return them in the
    5860             :  * ExtensionInfo* structure
    5861             :  *
    5862             :  *  numExtensions is set to the number of extensions read in
    5863             :  */
    5864             : ExtensionInfo *
    5865         322 : getExtensions(Archive *fout, int *numExtensions)
    5866             : {
    5867         322 :     DumpOptions *dopt = fout->dopt;
    5868             :     PGresult   *res;
    5869             :     int         ntups;
    5870             :     int         i;
    5871             :     PQExpBuffer query;
    5872         322 :     ExtensionInfo *extinfo = NULL;
    5873             :     int         i_tableoid;
    5874             :     int         i_oid;
    5875             :     int         i_extname;
    5876             :     int         i_nspname;
    5877             :     int         i_extrelocatable;
    5878             :     int         i_extversion;
    5879             :     int         i_extconfig;
    5880             :     int         i_extcondition;
    5881             : 
    5882         322 :     query = createPQExpBuffer();
    5883             : 
    5884         322 :     appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
    5885             :                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
    5886             :                          "FROM pg_extension x "
    5887             :                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
    5888             : 
    5889         322 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5890             : 
    5891         322 :     ntups = PQntuples(res);
    5892         322 :     if (ntups == 0)
    5893           0 :         goto cleanup;
    5894             : 
    5895         322 :     extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
    5896             : 
    5897         322 :     i_tableoid = PQfnumber(res, "tableoid");
    5898         322 :     i_oid = PQfnumber(res, "oid");
    5899         322 :     i_extname = PQfnumber(res, "extname");
    5900         322 :     i_nspname = PQfnumber(res, "nspname");
    5901         322 :     i_extrelocatable = PQfnumber(res, "extrelocatable");
    5902         322 :     i_extversion = PQfnumber(res, "extversion");
    5903         322 :     i_extconfig = PQfnumber(res, "extconfig");
    5904         322 :     i_extcondition = PQfnumber(res, "extcondition");
    5905             : 
    5906         694 :     for (i = 0; i < ntups; i++)
    5907             :     {
    5908         372 :         extinfo[i].dobj.objType = DO_EXTENSION;
    5909         372 :         extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    5910         372 :         extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    5911         372 :         AssignDumpId(&extinfo[i].dobj);
    5912         372 :         extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
    5913         372 :         extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
    5914         372 :         extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
    5915         372 :         extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
    5916         372 :         extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
    5917         372 :         extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
    5918             : 
    5919             :         /* Decide whether we want to dump it */
    5920         372 :         selectDumpableExtension(&(extinfo[i]), dopt);
    5921             :     }
    5922             : 
    5923         322 : cleanup:
    5924         322 :     PQclear(res);
    5925         322 :     destroyPQExpBuffer(query);
    5926             : 
    5927         322 :     *numExtensions = ntups;
    5928             : 
    5929         322 :     return extinfo;
    5930             : }
    5931             : 
    5932             : /*
    5933             :  * getTypes:
    5934             :  *    get information about all types in the system catalogs
    5935             :  *
    5936             :  * NB: this must run after getFuncs() because we assume we can do
    5937             :  * findFuncByOid().
    5938             :  */
    5939             : void
    5940         320 : getTypes(Archive *fout)
    5941             : {
    5942             :     PGresult   *res;
    5943             :     int         ntups;
    5944             :     int         i;
    5945         320 :     PQExpBuffer query = createPQExpBuffer();
    5946             :     TypeInfo   *tyinfo;
    5947             :     ShellTypeInfo *stinfo;
    5948             :     int         i_tableoid;
    5949             :     int         i_oid;
    5950             :     int         i_typname;
    5951             :     int         i_typnamespace;
    5952             :     int         i_typacl;
    5953             :     int         i_acldefault;
    5954             :     int         i_typowner;
    5955             :     int         i_typelem;
    5956             :     int         i_typrelid;
    5957             :     int         i_typrelkind;
    5958             :     int         i_typtype;
    5959             :     int         i_typisdefined;
    5960             :     int         i_isarray;
    5961             :     int         i_typarray;
    5962             : 
    5963             :     /*
    5964             :      * we include even the built-in types because those may be used as array
    5965             :      * elements by user-defined types
    5966             :      *
    5967             :      * we filter out the built-in types when we dump out the types
    5968             :      *
    5969             :      * same approach for undefined (shell) types and array types
    5970             :      *
    5971             :      * Note: as of 8.3 we can reliably detect whether a type is an
    5972             :      * auto-generated array type by checking the element type's typarray.
    5973             :      * (Before that the test is capable of generating false positives.) We
    5974             :      * still check for name beginning with '_', though, so as to avoid the
    5975             :      * cost of the subselect probe for all standard types.  This would have to
    5976             :      * be revisited if the backend ever allows renaming of array types.
    5977             :      */
    5978         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
    5979             :                          "typnamespace, typacl, "
    5980             :                          "acldefault('T', typowner) AS acldefault, "
    5981             :                          "typowner, "
    5982             :                          "typelem, typrelid, typarray, "
    5983             :                          "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
    5984             :                          "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
    5985             :                          "typtype, typisdefined, "
    5986             :                          "typname[0] = '_' AND typelem != 0 AND "
    5987             :                          "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
    5988             :                          "FROM pg_type");
    5989             : 
    5990         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    5991             : 
    5992         320 :     ntups = PQntuples(res);
    5993             : 
    5994         320 :     tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
    5995             : 
    5996         320 :     i_tableoid = PQfnumber(res, "tableoid");
    5997         320 :     i_oid = PQfnumber(res, "oid");
    5998         320 :     i_typname = PQfnumber(res, "typname");
    5999         320 :     i_typnamespace = PQfnumber(res, "typnamespace");
    6000         320 :     i_typacl = PQfnumber(res, "typacl");
    6001         320 :     i_acldefault = PQfnumber(res, "acldefault");
    6002         320 :     i_typowner = PQfnumber(res, "typowner");
    6003         320 :     i_typelem = PQfnumber(res, "typelem");
    6004         320 :     i_typrelid = PQfnumber(res, "typrelid");
    6005         320 :     i_typrelkind = PQfnumber(res, "typrelkind");
    6006         320 :     i_typtype = PQfnumber(res, "typtype");
    6007         320 :     i_typisdefined = PQfnumber(res, "typisdefined");
    6008         320 :     i_isarray = PQfnumber(res, "isarray");
    6009         320 :     i_typarray = PQfnumber(res, "typarray");
    6010             : 
    6011      232308 :     for (i = 0; i < ntups; i++)
    6012             :     {
    6013      231988 :         tyinfo[i].dobj.objType = DO_TYPE;
    6014      231988 :         tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6015      231988 :         tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6016      231988 :         AssignDumpId(&tyinfo[i].dobj);
    6017      231988 :         tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
    6018      463976 :         tyinfo[i].dobj.namespace =
    6019      231988 :             findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
    6020      231988 :         tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
    6021      231988 :         tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6022      231988 :         tyinfo[i].dacl.privtype = 0;
    6023      231988 :         tyinfo[i].dacl.initprivs = NULL;
    6024      231988 :         tyinfo[i].ftypname = NULL;  /* may get filled later */
    6025      231988 :         tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
    6026      231988 :         tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
    6027      231988 :         tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
    6028      231988 :         tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
    6029      231988 :         tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
    6030      231988 :         tyinfo[i].shellType = NULL;
    6031             : 
    6032      231988 :         if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
    6033      231880 :             tyinfo[i].isDefined = true;
    6034             :         else
    6035         108 :             tyinfo[i].isDefined = false;
    6036             : 
    6037      231988 :         if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
    6038      111300 :             tyinfo[i].isArray = true;
    6039             :         else
    6040      120688 :             tyinfo[i].isArray = false;
    6041             : 
    6042      231988 :         tyinfo[i].typarray = atooid(PQgetvalue(res, i, i_typarray));
    6043             : 
    6044      231988 :         if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
    6045        2192 :             tyinfo[i].isMultirange = true;
    6046             :         else
    6047      229796 :             tyinfo[i].isMultirange = false;
    6048             : 
    6049             :         /* Decide whether we want to dump it */
    6050      231988 :         selectDumpableType(&tyinfo[i], fout);
    6051             : 
    6052             :         /* Mark whether type has an ACL */
    6053      231988 :         if (!PQgetisnull(res, i, i_typacl))
    6054         426 :             tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6055             : 
    6056             :         /*
    6057             :          * If it's a domain, fetch info about its constraints, if any
    6058             :          */
    6059      231988 :         tyinfo[i].nDomChecks = 0;
    6060      231988 :         tyinfo[i].domChecks = NULL;
    6061      231988 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6062       28530 :             tyinfo[i].typtype == TYPTYPE_DOMAIN)
    6063         290 :             getDomainConstraints(fout, &(tyinfo[i]));
    6064             : 
    6065             :         /*
    6066             :          * If it's a base type, make a DumpableObject representing a shell
    6067             :          * definition of the type.  We will need to dump that ahead of the I/O
    6068             :          * functions for the type.  Similarly, range types need a shell
    6069             :          * definition in case they have a canonicalize function.
    6070             :          *
    6071             :          * Note: the shell type doesn't have a catId.  You might think it
    6072             :          * should copy the base type's catId, but then it might capture the
    6073             :          * pg_depend entries for the type, which we don't want.
    6074             :          */
    6075      231988 :         if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
    6076       28530 :             (tyinfo[i].typtype == TYPTYPE_BASE ||
    6077       13842 :              tyinfo[i].typtype == TYPTYPE_RANGE))
    6078             :         {
    6079       14944 :             stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
    6080       14944 :             stinfo->dobj.objType = DO_SHELL_TYPE;
    6081       14944 :             stinfo->dobj.catId = nilCatalogId;
    6082       14944 :             AssignDumpId(&stinfo->dobj);
    6083       14944 :             stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
    6084       14944 :             stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
    6085       14944 :             stinfo->baseType = &(tyinfo[i]);
    6086       14944 :             tyinfo[i].shellType = stinfo;
    6087             : 
    6088             :             /*
    6089             :              * Initially mark the shell type as not to be dumped.  We'll only
    6090             :              * dump it if the I/O or canonicalize functions need to be dumped;
    6091             :              * this is taken care of while sorting dependencies.
    6092             :              */
    6093       14944 :             stinfo->dobj.dump = DUMP_COMPONENT_NONE;
    6094             :         }
    6095             :     }
    6096             : 
    6097         320 :     PQclear(res);
    6098             : 
    6099         320 :     destroyPQExpBuffer(query);
    6100         320 : }
    6101             : 
    6102             : /*
    6103             :  * getOperators:
    6104             :  *    get information about all operators in the system catalogs
    6105             :  */
    6106             : void
    6107         320 : getOperators(Archive *fout)
    6108             : {
    6109             :     PGresult   *res;
    6110             :     int         ntups;
    6111             :     int         i;
    6112         320 :     PQExpBuffer query = createPQExpBuffer();
    6113             :     OprInfo    *oprinfo;
    6114             :     int         i_tableoid;
    6115             :     int         i_oid;
    6116             :     int         i_oprname;
    6117             :     int         i_oprnamespace;
    6118             :     int         i_oprowner;
    6119             :     int         i_oprkind;
    6120             :     int         i_oprcode;
    6121             : 
    6122             :     /*
    6123             :      * find all operators, including builtin operators; we filter out
    6124             :      * system-defined operators at dump-out time.
    6125             :      */
    6126             : 
    6127         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
    6128             :                          "oprnamespace, "
    6129             :                          "oprowner, "
    6130             :                          "oprkind, "
    6131             :                          "oprcode::oid AS oprcode "
    6132             :                          "FROM pg_operator");
    6133             : 
    6134         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6135             : 
    6136         320 :     ntups = PQntuples(res);
    6137             : 
    6138         320 :     oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
    6139             : 
    6140         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6141         320 :     i_oid = PQfnumber(res, "oid");
    6142         320 :     i_oprname = PQfnumber(res, "oprname");
    6143         320 :     i_oprnamespace = PQfnumber(res, "oprnamespace");
    6144         320 :     i_oprowner = PQfnumber(res, "oprowner");
    6145         320 :     i_oprkind = PQfnumber(res, "oprkind");
    6146         320 :     i_oprcode = PQfnumber(res, "oprcode");
    6147             : 
    6148      256288 :     for (i = 0; i < ntups; i++)
    6149             :     {
    6150      255968 :         oprinfo[i].dobj.objType = DO_OPERATOR;
    6151      255968 :         oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6152      255968 :         oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6153      255968 :         AssignDumpId(&oprinfo[i].dobj);
    6154      255968 :         oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
    6155      511936 :         oprinfo[i].dobj.namespace =
    6156      255968 :             findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
    6157      255968 :         oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
    6158      255968 :         oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
    6159      255968 :         oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
    6160             : 
    6161             :         /* Decide whether we want to dump it */
    6162      255968 :         selectDumpableObject(&(oprinfo[i].dobj), fout);
    6163             :     }
    6164             : 
    6165         320 :     PQclear(res);
    6166             : 
    6167         320 :     destroyPQExpBuffer(query);
    6168         320 : }
    6169             : 
    6170             : /*
    6171             :  * getCollations:
    6172             :  *    get information about all collations in the system catalogs
    6173             :  */
    6174             : void
    6175         320 : getCollations(Archive *fout)
    6176             : {
    6177             :     PGresult   *res;
    6178             :     int         ntups;
    6179             :     int         i;
    6180             :     PQExpBuffer query;
    6181             :     CollInfo   *collinfo;
    6182             :     int         i_tableoid;
    6183             :     int         i_oid;
    6184             :     int         i_collname;
    6185             :     int         i_collnamespace;
    6186             :     int         i_collowner;
    6187             : 
    6188         320 :     query = createPQExpBuffer();
    6189             : 
    6190             :     /*
    6191             :      * find all collations, including builtin collations; we filter out
    6192             :      * system-defined collations at dump-out time.
    6193             :      */
    6194             : 
    6195         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
    6196             :                          "collnamespace, "
    6197             :                          "collowner "
    6198             :                          "FROM pg_collation");
    6199             : 
    6200         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6201             : 
    6202         320 :     ntups = PQntuples(res);
    6203             : 
    6204         320 :     collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
    6205             : 
    6206         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6207         320 :     i_oid = PQfnumber(res, "oid");
    6208         320 :     i_collname = PQfnumber(res, "collname");
    6209         320 :     i_collnamespace = PQfnumber(res, "collnamespace");
    6210         320 :     i_collowner = PQfnumber(res, "collowner");
    6211             : 
    6212      254310 :     for (i = 0; i < ntups; i++)
    6213             :     {
    6214      253990 :         collinfo[i].dobj.objType = DO_COLLATION;
    6215      253990 :         collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6216      253990 :         collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6217      253990 :         AssignDumpId(&collinfo[i].dobj);
    6218      253990 :         collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
    6219      507980 :         collinfo[i].dobj.namespace =
    6220      253990 :             findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
    6221      253990 :         collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
    6222             : 
    6223             :         /* Decide whether we want to dump it */
    6224      253990 :         selectDumpableObject(&(collinfo[i].dobj), fout);
    6225             :     }
    6226             : 
    6227         320 :     PQclear(res);
    6228             : 
    6229         320 :     destroyPQExpBuffer(query);
    6230         320 : }
    6231             : 
    6232             : /*
    6233             :  * getConversions:
    6234             :  *    get information about all conversions in the system catalogs
    6235             :  */
    6236             : void
    6237         320 : getConversions(Archive *fout)
    6238             : {
    6239             :     PGresult   *res;
    6240             :     int         ntups;
    6241             :     int         i;
    6242             :     PQExpBuffer query;
    6243             :     ConvInfo   *convinfo;
    6244             :     int         i_tableoid;
    6245             :     int         i_oid;
    6246             :     int         i_conname;
    6247             :     int         i_connamespace;
    6248             :     int         i_conowner;
    6249             : 
    6250         320 :     query = createPQExpBuffer();
    6251             : 
    6252             :     /*
    6253             :      * find all conversions, including builtin conversions; we filter out
    6254             :      * system-defined conversions at dump-out time.
    6255             :      */
    6256             : 
    6257         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
    6258             :                          "connamespace, "
    6259             :                          "conowner "
    6260             :                          "FROM pg_conversion");
    6261             : 
    6262         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6263             : 
    6264         320 :     ntups = PQntuples(res);
    6265             : 
    6266         320 :     convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
    6267             : 
    6268         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6269         320 :     i_oid = PQfnumber(res, "oid");
    6270         320 :     i_conname = PQfnumber(res, "conname");
    6271         320 :     i_connamespace = PQfnumber(res, "connamespace");
    6272         320 :     i_conowner = PQfnumber(res, "conowner");
    6273             : 
    6274       41374 :     for (i = 0; i < ntups; i++)
    6275             :     {
    6276       41054 :         convinfo[i].dobj.objType = DO_CONVERSION;
    6277       41054 :         convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6278       41054 :         convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6279       41054 :         AssignDumpId(&convinfo[i].dobj);
    6280       41054 :         convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    6281       82108 :         convinfo[i].dobj.namespace =
    6282       41054 :             findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
    6283       41054 :         convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
    6284             : 
    6285             :         /* Decide whether we want to dump it */
    6286       41054 :         selectDumpableObject(&(convinfo[i].dobj), fout);
    6287             :     }
    6288             : 
    6289         320 :     PQclear(res);
    6290             : 
    6291         320 :     destroyPQExpBuffer(query);
    6292         320 : }
    6293             : 
    6294             : /*
    6295             :  * getAccessMethods:
    6296             :  *    get information about all user-defined access methods
    6297             :  */
    6298             : void
    6299         320 : getAccessMethods(Archive *fout)
    6300             : {
    6301             :     PGresult   *res;
    6302             :     int         ntups;
    6303             :     int         i;
    6304             :     PQExpBuffer query;
    6305             :     AccessMethodInfo *aminfo;
    6306             :     int         i_tableoid;
    6307             :     int         i_oid;
    6308             :     int         i_amname;
    6309             :     int         i_amhandler;
    6310             :     int         i_amtype;
    6311             : 
    6312             :     /* Before 9.6, there are no user-defined access methods */
    6313         320 :     if (fout->remoteVersion < 90600)
    6314           0 :         return;
    6315             : 
    6316         320 :     query = createPQExpBuffer();
    6317             : 
    6318             :     /* Select all access methods from pg_am table */
    6319         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
    6320             :                          "amhandler::pg_catalog.regproc AS amhandler "
    6321             :                          "FROM pg_am");
    6322             : 
    6323         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6324             : 
    6325         320 :     ntups = PQntuples(res);
    6326             : 
    6327         320 :     aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
    6328             : 
    6329         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6330         320 :     i_oid = PQfnumber(res, "oid");
    6331         320 :     i_amname = PQfnumber(res, "amname");
    6332         320 :     i_amhandler = PQfnumber(res, "amhandler");
    6333         320 :     i_amtype = PQfnumber(res, "amtype");
    6334             : 
    6335        2812 :     for (i = 0; i < ntups; i++)
    6336             :     {
    6337        2492 :         aminfo[i].dobj.objType = DO_ACCESS_METHOD;
    6338        2492 :         aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6339        2492 :         aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6340        2492 :         AssignDumpId(&aminfo[i].dobj);
    6341        2492 :         aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
    6342        2492 :         aminfo[i].dobj.namespace = NULL;
    6343        2492 :         aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
    6344        2492 :         aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
    6345             : 
    6346             :         /* Decide whether we want to dump it */
    6347        2492 :         selectDumpableAccessMethod(&(aminfo[i]), fout);
    6348             :     }
    6349             : 
    6350         320 :     PQclear(res);
    6351             : 
    6352         320 :     destroyPQExpBuffer(query);
    6353             : }
    6354             : 
    6355             : 
    6356             : /*
    6357             :  * getOpclasses:
    6358             :  *    get information about all opclasses in the system catalogs
    6359             :  */
    6360             : void
    6361         320 : getOpclasses(Archive *fout)
    6362             : {
    6363             :     PGresult   *res;
    6364             :     int         ntups;
    6365             :     int         i;
    6366         320 :     PQExpBuffer query = createPQExpBuffer();
    6367             :     OpclassInfo *opcinfo;
    6368             :     int         i_tableoid;
    6369             :     int         i_oid;
    6370             :     int         i_opcname;
    6371             :     int         i_opcnamespace;
    6372             :     int         i_opcowner;
    6373             : 
    6374             :     /*
    6375             :      * find all opclasses, including builtin opclasses; we filter out
    6376             :      * system-defined opclasses at dump-out time.
    6377             :      */
    6378             : 
    6379         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
    6380             :                          "opcnamespace, "
    6381             :                          "opcowner "
    6382             :                          "FROM pg_opclass");
    6383             : 
    6384         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6385             : 
    6386         320 :     ntups = PQntuples(res);
    6387             : 
    6388         320 :     opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
    6389             : 
    6390         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6391         320 :     i_oid = PQfnumber(res, "oid");
    6392         320 :     i_opcname = PQfnumber(res, "opcname");
    6393         320 :     i_opcnamespace = PQfnumber(res, "opcnamespace");
    6394         320 :     i_opcowner = PQfnumber(res, "opcowner");
    6395             : 
    6396       57284 :     for (i = 0; i < ntups; i++)
    6397             :     {
    6398       56964 :         opcinfo[i].dobj.objType = DO_OPCLASS;
    6399       56964 :         opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6400       56964 :         opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6401       56964 :         AssignDumpId(&opcinfo[i].dobj);
    6402       56964 :         opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
    6403      113928 :         opcinfo[i].dobj.namespace =
    6404       56964 :             findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
    6405       56964 :         opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
    6406             : 
    6407             :         /* Decide whether we want to dump it */
    6408       56964 :         selectDumpableObject(&(opcinfo[i].dobj), fout);
    6409             :     }
    6410             : 
    6411         320 :     PQclear(res);
    6412             : 
    6413         320 :     destroyPQExpBuffer(query);
    6414         320 : }
    6415             : 
    6416             : /*
    6417             :  * getOpfamilies:
    6418             :  *    get information about all opfamilies in the system catalogs
    6419             :  */
    6420             : void
    6421         320 : getOpfamilies(Archive *fout)
    6422             : {
    6423             :     PGresult   *res;
    6424             :     int         ntups;
    6425             :     int         i;
    6426             :     PQExpBuffer query;
    6427             :     OpfamilyInfo *opfinfo;
    6428             :     int         i_tableoid;
    6429             :     int         i_oid;
    6430             :     int         i_opfname;
    6431             :     int         i_opfnamespace;
    6432             :     int         i_opfowner;
    6433             : 
    6434         320 :     query = createPQExpBuffer();
    6435             : 
    6436             :     /*
    6437             :      * find all opfamilies, including builtin opfamilies; we filter out
    6438             :      * system-defined opfamilies at dump-out time.
    6439             :      */
    6440             : 
    6441         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
    6442             :                          "opfnamespace, "
    6443             :                          "opfowner "
    6444             :                          "FROM pg_opfamily");
    6445             : 
    6446         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6447             : 
    6448         320 :     ntups = PQntuples(res);
    6449             : 
    6450         320 :     opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
    6451             : 
    6452         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6453         320 :     i_oid = PQfnumber(res, "oid");
    6454         320 :     i_opfname = PQfnumber(res, "opfname");
    6455         320 :     i_opfnamespace = PQfnumber(res, "opfnamespace");
    6456         320 :     i_opfowner = PQfnumber(res, "opfowner");
    6457             : 
    6458       47326 :     for (i = 0; i < ntups; i++)
    6459             :     {
    6460       47006 :         opfinfo[i].dobj.objType = DO_OPFAMILY;
    6461       47006 :         opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6462       47006 :         opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6463       47006 :         AssignDumpId(&opfinfo[i].dobj);
    6464       47006 :         opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
    6465       94012 :         opfinfo[i].dobj.namespace =
    6466       47006 :             findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
    6467       47006 :         opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
    6468             : 
    6469             :         /* Decide whether we want to dump it */
    6470       47006 :         selectDumpableObject(&(opfinfo[i].dobj), fout);
    6471             :     }
    6472             : 
    6473         320 :     PQclear(res);
    6474             : 
    6475         320 :     destroyPQExpBuffer(query);
    6476         320 : }
    6477             : 
    6478             : /*
    6479             :  * getAggregates:
    6480             :  *    get information about all user-defined aggregates in the system catalogs
    6481             :  */
    6482             : void
    6483         320 : getAggregates(Archive *fout)
    6484             : {
    6485         320 :     DumpOptions *dopt = fout->dopt;
    6486             :     PGresult   *res;
    6487             :     int         ntups;
    6488             :     int         i;
    6489         320 :     PQExpBuffer query = createPQExpBuffer();
    6490             :     AggInfo    *agginfo;
    6491             :     int         i_tableoid;
    6492             :     int         i_oid;
    6493             :     int         i_aggname;
    6494             :     int         i_aggnamespace;
    6495             :     int         i_pronargs;
    6496             :     int         i_proargtypes;
    6497             :     int         i_proowner;
    6498             :     int         i_aggacl;
    6499             :     int         i_acldefault;
    6500             : 
    6501             :     /*
    6502             :      * Find all interesting aggregates.  See comment in getFuncs() for the
    6503             :      * rationale behind the filtering logic.
    6504             :      */
    6505         320 :     if (fout->remoteVersion >= 90600)
    6506             :     {
    6507             :         const char *agg_check;
    6508             : 
    6509         640 :         agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
    6510         320 :                      : "p.proisagg");
    6511             : 
    6512         320 :         appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
    6513             :                           "p.proname AS aggname, "
    6514             :                           "p.pronamespace AS aggnamespace, "
    6515             :                           "p.pronargs, p.proargtypes, "
    6516             :                           "p.proowner, "
    6517             :                           "p.proacl AS aggacl, "
    6518             :                           "acldefault('f', p.proowner) AS acldefault "
    6519             :                           "FROM pg_proc p "
    6520             :                           "LEFT JOIN pg_init_privs pip ON "
    6521             :                           "(p.oid = pip.objoid "
    6522             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6523             :                           "AND pip.objsubid = 0) "
    6524             :                           "WHERE %s AND ("
    6525             :                           "p.pronamespace != "
    6526             :                           "(SELECT oid FROM pg_namespace "
    6527             :                           "WHERE nspname = 'pg_catalog') OR "
    6528             :                           "p.proacl IS DISTINCT FROM pip.initprivs",
    6529             :                           agg_check);
    6530         320 :         if (dopt->binary_upgrade)
    6531          32 :             appendPQExpBufferStr(query,
    6532             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6533             :                                  "classid = 'pg_proc'::regclass AND "
    6534             :                                  "objid = p.oid AND "
    6535             :                                  "refclassid = 'pg_extension'::regclass AND "
    6536             :                                  "deptype = 'e')");
    6537         320 :         appendPQExpBufferChar(query, ')');
    6538             :     }
    6539             :     else
    6540             :     {
    6541           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
    6542             :                              "pronamespace AS aggnamespace, "
    6543             :                              "pronargs, proargtypes, "
    6544             :                              "proowner, "
    6545             :                              "proacl AS aggacl, "
    6546             :                              "acldefault('f', proowner) AS acldefault "
    6547             :                              "FROM pg_proc p "
    6548             :                              "WHERE proisagg AND ("
    6549             :                              "pronamespace != "
    6550             :                              "(SELECT oid FROM pg_namespace "
    6551             :                              "WHERE nspname = 'pg_catalog')");
    6552           0 :         if (dopt->binary_upgrade)
    6553           0 :             appendPQExpBufferStr(query,
    6554             :                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6555             :                                  "classid = 'pg_proc'::regclass AND "
    6556             :                                  "objid = p.oid AND "
    6557             :                                  "refclassid = 'pg_extension'::regclass AND "
    6558             :                                  "deptype = 'e')");
    6559           0 :         appendPQExpBufferChar(query, ')');
    6560             :     }
    6561             : 
    6562         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6563             : 
    6564         320 :     ntups = PQntuples(res);
    6565             : 
    6566         320 :     agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
    6567             : 
    6568         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6569         320 :     i_oid = PQfnumber(res, "oid");
    6570         320 :     i_aggname = PQfnumber(res, "aggname");
    6571         320 :     i_aggnamespace = PQfnumber(res, "aggnamespace");
    6572         320 :     i_pronargs = PQfnumber(res, "pronargs");
    6573         320 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6574         320 :     i_proowner = PQfnumber(res, "proowner");
    6575         320 :     i_aggacl = PQfnumber(res, "aggacl");
    6576         320 :     i_acldefault = PQfnumber(res, "acldefault");
    6577             : 
    6578        1122 :     for (i = 0; i < ntups; i++)
    6579             :     {
    6580         802 :         agginfo[i].aggfn.dobj.objType = DO_AGG;
    6581         802 :         agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6582         802 :         agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6583         802 :         AssignDumpId(&agginfo[i].aggfn.dobj);
    6584         802 :         agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
    6585        1604 :         agginfo[i].aggfn.dobj.namespace =
    6586         802 :             findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
    6587         802 :         agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
    6588         802 :         agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6589         802 :         agginfo[i].aggfn.dacl.privtype = 0;
    6590         802 :         agginfo[i].aggfn.dacl.initprivs = NULL;
    6591         802 :         agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6592         802 :         agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
    6593         802 :         agginfo[i].aggfn.prorettype = InvalidOid;   /* not saved */
    6594         802 :         agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6595         802 :         if (agginfo[i].aggfn.nargs == 0)
    6596         112 :             agginfo[i].aggfn.argtypes = NULL;
    6597             :         else
    6598             :         {
    6599         690 :             agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
    6600         690 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6601         690 :                           agginfo[i].aggfn.argtypes,
    6602         690 :                           agginfo[i].aggfn.nargs);
    6603             :         }
    6604         802 :         agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
    6605             : 
    6606             :         /* Decide whether we want to dump it */
    6607         802 :         selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
    6608             : 
    6609             :         /* Mark whether aggregate has an ACL */
    6610         802 :         if (!PQgetisnull(res, i, i_aggacl))
    6611          50 :             agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
    6612             :     }
    6613             : 
    6614         320 :     PQclear(res);
    6615             : 
    6616         320 :     destroyPQExpBuffer(query);
    6617         320 : }
    6618             : 
    6619             : /*
    6620             :  * getFuncs:
    6621             :  *    get information about all user-defined functions in the system catalogs
    6622             :  */
    6623             : void
    6624         320 : getFuncs(Archive *fout)
    6625             : {
    6626         320 :     DumpOptions *dopt = fout->dopt;
    6627             :     PGresult   *res;
    6628             :     int         ntups;
    6629             :     int         i;
    6630         320 :     PQExpBuffer query = createPQExpBuffer();
    6631             :     FuncInfo   *finfo;
    6632             :     int         i_tableoid;
    6633             :     int         i_oid;
    6634             :     int         i_proname;
    6635             :     int         i_pronamespace;
    6636             :     int         i_proowner;
    6637             :     int         i_prolang;
    6638             :     int         i_pronargs;
    6639             :     int         i_proargtypes;
    6640             :     int         i_prorettype;
    6641             :     int         i_proacl;
    6642             :     int         i_acldefault;
    6643             : 
    6644             :     /*
    6645             :      * Find all interesting functions.  This is a bit complicated:
    6646             :      *
    6647             :      * 1. Always exclude aggregates; those are handled elsewhere.
    6648             :      *
    6649             :      * 2. Always exclude functions that are internally dependent on something
    6650             :      * else, since presumably those will be created as a result of creating
    6651             :      * the something else.  This currently acts only to suppress constructor
    6652             :      * functions for range types.  Note this is OK only because the
    6653             :      * constructors don't have any dependencies the range type doesn't have;
    6654             :      * otherwise we might not get creation ordering correct.
    6655             :      *
    6656             :      * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
    6657             :      * they're members of extensions and we are in binary-upgrade mode then
    6658             :      * include them, since we want to dump extension members individually in
    6659             :      * that mode.  Also, if they are used by casts or transforms then we need
    6660             :      * to gather the information about them, though they won't be dumped if
    6661             :      * they are built-in.  Also, in 9.6 and up, include functions in
    6662             :      * pg_catalog if they have an ACL different from what's shown in
    6663             :      * pg_init_privs (so we have to join to pg_init_privs; annoying).
    6664             :      */
    6665         320 :     if (fout->remoteVersion >= 90600)
    6666             :     {
    6667             :         const char *not_agg_check;
    6668             : 
    6669         640 :         not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
    6670         320 :                          : "NOT p.proisagg");
    6671             : 
    6672         320 :         appendPQExpBuffer(query,
    6673             :                           "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
    6674             :                           "p.pronargs, p.proargtypes, p.prorettype, "
    6675             :                           "p.proacl, "
    6676             :                           "acldefault('f', p.proowner) AS acldefault, "
    6677             :                           "p.pronamespace, "
    6678             :                           "p.proowner "
    6679             :                           "FROM pg_proc p "
    6680             :                           "LEFT JOIN pg_init_privs pip ON "
    6681             :                           "(p.oid = pip.objoid "
    6682             :                           "AND pip.classoid = 'pg_proc'::regclass "
    6683             :                           "AND pip.objsubid = 0) "
    6684             :                           "WHERE %s"
    6685             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6686             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6687             :                           "objid = p.oid AND deptype = 'i')"
    6688             :                           "\n  AND ("
    6689             :                           "\n  pronamespace != "
    6690             :                           "(SELECT oid FROM pg_namespace "
    6691             :                           "WHERE nspname = 'pg_catalog')"
    6692             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6693             :                           "\n  WHERE pg_cast.oid > %u "
    6694             :                           "\n  AND p.oid = pg_cast.castfunc)"
    6695             :                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6696             :                           "\n  WHERE pg_transform.oid > %u AND "
    6697             :                           "\n  (p.oid = pg_transform.trffromsql"
    6698             :                           "\n  OR p.oid = pg_transform.trftosql))",
    6699             :                           not_agg_check,
    6700             :                           g_last_builtin_oid,
    6701             :                           g_last_builtin_oid);
    6702         320 :         if (dopt->binary_upgrade)
    6703          32 :             appendPQExpBufferStr(query,
    6704             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6705             :                                  "classid = 'pg_proc'::regclass AND "
    6706             :                                  "objid = p.oid AND "
    6707             :                                  "refclassid = 'pg_extension'::regclass AND "
    6708             :                                  "deptype = 'e')");
    6709         320 :         appendPQExpBufferStr(query,
    6710             :                              "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
    6711         320 :         appendPQExpBufferChar(query, ')');
    6712             :     }
    6713             :     else
    6714             :     {
    6715           0 :         appendPQExpBuffer(query,
    6716             :                           "SELECT tableoid, oid, proname, prolang, "
    6717             :                           "pronargs, proargtypes, prorettype, proacl, "
    6718             :                           "acldefault('f', proowner) AS acldefault, "
    6719             :                           "pronamespace, "
    6720             :                           "proowner "
    6721             :                           "FROM pg_proc p "
    6722             :                           "WHERE NOT proisagg"
    6723             :                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
    6724             :                           "WHERE classid = 'pg_proc'::regclass AND "
    6725             :                           "objid = p.oid AND deptype = 'i')"
    6726             :                           "\n  AND ("
    6727             :                           "\n  pronamespace != "
    6728             :                           "(SELECT oid FROM pg_namespace "
    6729             :                           "WHERE nspname = 'pg_catalog')"
    6730             :                           "\n  OR EXISTS (SELECT 1 FROM pg_cast"
    6731             :                           "\n  WHERE pg_cast.oid > '%u'::oid"
    6732             :                           "\n  AND p.oid = pg_cast.castfunc)",
    6733             :                           g_last_builtin_oid);
    6734             : 
    6735           0 :         if (fout->remoteVersion >= 90500)
    6736           0 :             appendPQExpBuffer(query,
    6737             :                               "\n  OR EXISTS (SELECT 1 FROM pg_transform"
    6738             :                               "\n  WHERE pg_transform.oid > '%u'::oid"
    6739             :                               "\n  AND (p.oid = pg_transform.trffromsql"
    6740             :                               "\n  OR p.oid = pg_transform.trftosql))",
    6741             :                               g_last_builtin_oid);
    6742             : 
    6743           0 :         if (dopt->binary_upgrade)
    6744           0 :             appendPQExpBufferStr(query,
    6745             :                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
    6746             :                                  "classid = 'pg_proc'::regclass AND "
    6747             :                                  "objid = p.oid AND "
    6748             :                                  "refclassid = 'pg_extension'::regclass AND "
    6749             :                                  "deptype = 'e')");
    6750           0 :         appendPQExpBufferChar(query, ')');
    6751             :     }
    6752             : 
    6753         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    6754             : 
    6755         320 :     ntups = PQntuples(res);
    6756             : 
    6757         320 :     finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
    6758             : 
    6759         320 :     i_tableoid = PQfnumber(res, "tableoid");
    6760         320 :     i_oid = PQfnumber(res, "oid");
    6761         320 :     i_proname = PQfnumber(res, "proname");
    6762         320 :     i_pronamespace = PQfnumber(res, "pronamespace");
    6763         320 :     i_proowner = PQfnumber(res, "proowner");
    6764         320 :     i_prolang = PQfnumber(res, "prolang");
    6765         320 :     i_pronargs = PQfnumber(res, "pronargs");
    6766         320 :     i_proargtypes = PQfnumber(res, "proargtypes");
    6767         320 :     i_prorettype = PQfnumber(res, "prorettype");
    6768         320 :     i_proacl = PQfnumber(res, "proacl");
    6769         320 :     i_acldefault = PQfnumber(res, "acldefault");
    6770             : 
    6771        9208 :     for (i = 0; i < ntups; i++)
    6772             :     {
    6773        8888 :         finfo[i].dobj.objType = DO_FUNC;
    6774        8888 :         finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    6775        8888 :         finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    6776        8888 :         AssignDumpId(&finfo[i].dobj);
    6777        8888 :         finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
    6778       17776 :         finfo[i].dobj.namespace =
    6779        8888 :             findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
    6780        8888 :         finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
    6781        8888 :         finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    6782        8888 :         finfo[i].dacl.privtype = 0;
    6783        8888 :         finfo[i].dacl.initprivs = NULL;
    6784        8888 :         finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
    6785        8888 :         finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
    6786        8888 :         finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
    6787        8888 :         finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
    6788        8888 :         if (finfo[i].nargs == 0)
    6789        2142 :             finfo[i].argtypes = NULL;
    6790             :         else
    6791             :         {
    6792        6746 :             finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
    6793        6746 :             parseOidArray(PQgetvalue(res, i, i_proargtypes),
    6794        6746 :                           finfo[i].argtypes, finfo[i].nargs);
    6795             :         }
    6796        8888 :         finfo[i].postponed_def = false; /* might get set during sort */
    6797             : 
    6798             :         /* Decide whether we want to dump it */
    6799        8888 :         selectDumpableObject(&(finfo[i].dobj), fout);
    6800             : 
    6801             :         /* Mark whether function has an ACL */
    6802        8888 :         if (!PQgetisnull(res, i, i_proacl))
    6803         288 :             finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    6804             :     }
    6805             : 
    6806         320 :     PQclear(res);
    6807             : 
    6808         320 :     destroyPQExpBuffer(query);
    6809         320 : }
    6810             : 
    6811             : /*
    6812             :  * getRelationStatistics
    6813             :  *    register the statistics object as a dependent of the relation.
    6814             :  *
    6815             :  */
    6816             : static RelStatsInfo *
    6817       18512 : getRelationStatistics(Archive *fout, DumpableObject *rel, char relkind)
    6818             : {
    6819       18512 :     if (!fout->dopt->dumpStatistics)
    6820        5072 :         return NULL;
    6821             : 
    6822       13440 :     if ((relkind == RELKIND_RELATION) ||
    6823        6112 :         (relkind == RELKIND_PARTITIONED_TABLE) ||
    6824        3110 :         (relkind == RELKIND_INDEX) ||
    6825        2222 :         (relkind == RELKIND_PARTITIONED_INDEX) ||
    6826             :         (relkind == RELKIND_MATVIEW))
    6827             :     {
    6828       11986 :         RelStatsInfo *info = pg_malloc0(sizeof(RelStatsInfo));
    6829       11986 :         DumpableObject *dobj = &info->dobj;
    6830             : 
    6831       11986 :         dobj->objType = DO_REL_STATS;
    6832       11986 :         dobj->catId.tableoid = 0;
    6833       11986 :         dobj->catId.oid = 0;
    6834       11986 :         AssignDumpId(dobj);
    6835       11986 :         dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
    6836       11986 :         dobj->dependencies[0] = rel->dumpId;
    6837       11986 :         dobj->nDeps = 1;
    6838       11986 :         dobj->allocDeps = 1;
    6839       11986 :         dobj->components |= DUMP_COMPONENT_STATISTICS;
    6840       11986 :         dobj->name = pg_strdup(rel->name);
    6841       11986 :         dobj->namespace = rel->namespace;
    6842       11986 :         info->relkind = relkind;
    6843       11986 :         info->postponed_def = false;
    6844             : 
    6845       11986 :         return info;
    6846             :     }
    6847        1454 :     return NULL;
    6848             : }
    6849             : 
    6850             : /*
    6851             :  * getTables
    6852             :  *    read all the tables (no indexes) in the system catalogs,
    6853             :  *    and return them as an array of TableInfo structures
    6854             :  *
    6855             :  * *numTables is set to the number of tables read in
    6856             :  */
    6857             : TableInfo *
    6858         322 : getTables(Archive *fout, int *numTables)
    6859             : {
    6860         322 :     DumpOptions *dopt = fout->dopt;
    6861             :     PGresult   *res;
    6862             :     int         ntups;
    6863             :     int         i;
    6864         322 :     PQExpBuffer query = createPQExpBuffer();
    6865             :     TableInfo  *tblinfo;
    6866             :     int         i_reltableoid;
    6867             :     int         i_reloid;
    6868             :     int         i_relname;
    6869             :     int         i_relnamespace;
    6870             :     int         i_relkind;
    6871             :     int         i_reltype;
    6872             :     int         i_relowner;
    6873             :     int         i_relchecks;
    6874             :     int         i_relhasindex;
    6875             :     int         i_relhasrules;
    6876             :     int         i_relpages;
    6877             :     int         i_toastpages;
    6878             :     int         i_owning_tab;
    6879             :     int         i_owning_col;
    6880             :     int         i_reltablespace;
    6881             :     int         i_relhasoids;
    6882             :     int         i_relhastriggers;
    6883             :     int         i_relpersistence;
    6884             :     int         i_relispopulated;
    6885             :     int         i_relreplident;
    6886             :     int         i_relrowsec;
    6887             :     int         i_relforcerowsec;
    6888             :     int         i_relfrozenxid;
    6889             :     int         i_toastfrozenxid;
    6890             :     int         i_toastoid;
    6891             :     int         i_relminmxid;
    6892             :     int         i_toastminmxid;
    6893             :     int         i_reloptions;
    6894             :     int         i_checkoption;
    6895             :     int         i_toastreloptions;
    6896             :     int         i_reloftype;
    6897             :     int         i_foreignserver;
    6898             :     int         i_amname;
    6899             :     int         i_is_identity_sequence;
    6900             :     int         i_relacl;
    6901             :     int         i_acldefault;
    6902             :     int         i_ispartition;
    6903             : 
    6904             :     /*
    6905             :      * Find all the tables and table-like objects.
    6906             :      *
    6907             :      * We must fetch all tables in this phase because otherwise we cannot
    6908             :      * correctly identify inherited columns, owned sequences, etc.
    6909             :      *
    6910             :      * We include system catalogs, so that we can work if a user table is
    6911             :      * defined to inherit from a system catalog (pretty weird, but...)
    6912             :      *
    6913             :      * Note: in this phase we should collect only a minimal amount of
    6914             :      * information about each table, basically just enough to decide if it is
    6915             :      * interesting.  In particular, since we do not yet have lock on any user
    6916             :      * table, we MUST NOT invoke any server-side data collection functions
    6917             :      * (for instance, pg_get_partkeydef()).  Those are likely to fail or give
    6918             :      * wrong answers if any concurrent DDL is happening.
    6919             :      */
    6920             : 
    6921         322 :     appendPQExpBufferStr(query,
    6922             :                          "SELECT c.tableoid, c.oid, c.relname, "
    6923             :                          "c.relnamespace, c.relkind, c.reltype, "
    6924             :                          "c.relowner, "
    6925             :                          "c.relchecks, "
    6926             :                          "c.relhasindex, c.relhasrules, c.relpages, "
    6927             :                          "c.relhastriggers, "
    6928             :                          "c.relpersistence, "
    6929             :                          "c.reloftype, "
    6930             :                          "c.relacl, "
    6931             :                          "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
    6932             :                          " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
    6933             :                          "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
    6934             :                          "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
    6935             :                          "ELSE 0 END AS foreignserver, "
    6936             :                          "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
    6937             :                          "tc.oid AS toid, "
    6938             :                          "tc.relpages AS toastpages, "
    6939             :                          "tc.reloptions AS toast_reloptions, "
    6940             :                          "d.refobjid AS owning_tab, "
    6941             :                          "d.refobjsubid AS owning_col, "
    6942             :                          "tsp.spcname AS reltablespace, ");
    6943             : 
    6944         322 :     if (fout->remoteVersion >= 120000)
    6945         322 :         appendPQExpBufferStr(query,
    6946             :                              "false AS relhasoids, ");
    6947             :     else
    6948           0 :         appendPQExpBufferStr(query,
    6949             :                              "c.relhasoids, ");
    6950             : 
    6951         322 :     if (fout->remoteVersion >= 90300)
    6952         322 :         appendPQExpBufferStr(query,
    6953             :                              "c.relispopulated, ");
    6954             :     else
    6955           0 :         appendPQExpBufferStr(query,
    6956             :                              "'t' as relispopulated, ");
    6957             : 
    6958         322 :     if (fout->remoteVersion >= 90400)
    6959         322 :         appendPQExpBufferStr(query,
    6960             :                              "c.relreplident, ");
    6961             :     else
    6962           0 :         appendPQExpBufferStr(query,
    6963             :                              "'d' AS relreplident, ");
    6964             : 
    6965         322 :     if (fout->remoteVersion >= 90500)
    6966         322 :         appendPQExpBufferStr(query,
    6967             :                              "c.relrowsecurity, c.relforcerowsecurity, ");
    6968             :     else
    6969           0 :         appendPQExpBufferStr(query,
    6970             :                              "false AS relrowsecurity, "
    6971             :                              "false AS relforcerowsecurity, ");
    6972             : 
    6973         322 :     if (fout->remoteVersion >= 90300)
    6974         322 :         appendPQExpBufferStr(query,
    6975             :                              "c.relminmxid, tc.relminmxid AS tminmxid, ");
    6976             :     else
    6977           0 :         appendPQExpBufferStr(query,
    6978             :                              "0 AS relminmxid, 0 AS tminmxid, ");
    6979             : 
    6980         322 :     if (fout->remoteVersion >= 90300)
    6981         322 :         appendPQExpBufferStr(query,
    6982             :                              "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
    6983             :                              "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
    6984             :                              "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
    6985             :     else
    6986           0 :         appendPQExpBufferStr(query,
    6987             :                              "c.reloptions, NULL AS checkoption, ");
    6988             : 
    6989         322 :     if (fout->remoteVersion >= 90600)
    6990         322 :         appendPQExpBufferStr(query,
    6991             :                              "am.amname, ");
    6992             :     else
    6993           0 :         appendPQExpBufferStr(query,
    6994             :                              "NULL AS amname, ");
    6995             : 
    6996         322 :     if (fout->remoteVersion >= 90600)
    6997         322 :         appendPQExpBufferStr(query,
    6998             :                              "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
    6999             :     else
    7000           0 :         appendPQExpBufferStr(query,
    7001             :                              "false AS is_identity_sequence, ");
    7002             : 
    7003         322 :     if (fout->remoteVersion >= 100000)
    7004         322 :         appendPQExpBufferStr(query,
    7005             :                              "c.relispartition AS ispartition ");
    7006             :     else
    7007           0 :         appendPQExpBufferStr(query,
    7008             :                              "false AS ispartition ");
    7009             : 
    7010             :     /*
    7011             :      * Left join to pg_depend to pick up dependency info linking sequences to
    7012             :      * their owning column, if any (note this dependency is AUTO except for
    7013             :      * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
    7014             :      * collect the spcname.
    7015             :      */
    7016         322 :     appendPQExpBufferStr(query,
    7017             :                          "\nFROM pg_class c\n"
    7018             :                          "LEFT JOIN pg_depend d ON "
    7019             :                          "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
    7020             :                          "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
    7021             :                          "d.objsubid = 0 AND "
    7022             :                          "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
    7023             :                          "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
    7024             : 
    7025             :     /*
    7026             :      * In 9.6 and up, left join to pg_am to pick up the amname.
    7027             :      */
    7028         322 :     if (fout->remoteVersion >= 90600)
    7029         322 :         appendPQExpBufferStr(query,
    7030             :                              "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
    7031             : 
    7032             :     /*
    7033             :      * We purposefully ignore toast OIDs for partitioned tables; the reason is
    7034             :      * that versions 10 and 11 have them, but later versions do not, so
    7035             :      * emitting them causes the upgrade to fail.
    7036             :      */
    7037         322 :     appendPQExpBufferStr(query,
    7038             :                          "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
    7039             :                          " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
    7040             :                          " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
    7041             : 
    7042             :     /*
    7043             :      * Restrict to interesting relkinds (in particular, not indexes).  Not all
    7044             :      * relkinds are possible in older servers, but it's not worth the trouble
    7045             :      * to emit a version-dependent list.
    7046             :      *
    7047             :      * Composite-type table entries won't be dumped as such, but we have to
    7048             :      * make a DumpableObject for them so that we can track dependencies of the
    7049             :      * composite type (pg_depend entries for columns of the composite type
    7050             :      * link to the pg_class entry not the pg_type entry).
    7051             :      */
    7052         322 :     appendPQExpBufferStr(query,
    7053             :                          "WHERE c.relkind IN ("
    7054             :                          CppAsString2(RELKIND_RELATION) ", "
    7055             :                          CppAsString2(RELKIND_SEQUENCE) ", "
    7056             :                          CppAsString2(RELKIND_VIEW) ", "
    7057             :                          CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
    7058             :                          CppAsString2(RELKIND_MATVIEW) ", "
    7059             :                          CppAsString2(RELKIND_FOREIGN_TABLE) ", "
    7060             :                          CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
    7061             :                          "ORDER BY c.oid");
    7062             : 
    7063         322 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7064             : 
    7065         322 :     ntups = PQntuples(res);
    7066             : 
    7067         322 :     *numTables = ntups;
    7068             : 
    7069             :     /*
    7070             :      * Extract data from result and lock dumpable tables.  We do the locking
    7071             :      * before anything else, to minimize the window wherein a table could
    7072             :      * disappear under us.
    7073             :      *
    7074             :      * Note that we have to save info about all tables here, even when dumping
    7075             :      * only one, because we don't yet know which tables might be inheritance
    7076             :      * ancestors of the target table.
    7077             :      */
    7078         322 :     tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
    7079             : 
    7080         322 :     i_reltableoid = PQfnumber(res, "tableoid");
    7081         322 :     i_reloid = PQfnumber(res, "oid");
    7082         322 :     i_relname = PQfnumber(res, "relname");
    7083         322 :     i_relnamespace = PQfnumber(res, "relnamespace");
    7084         322 :     i_relkind = PQfnumber(res, "relkind");
    7085         322 :     i_reltype = PQfnumber(res, "reltype");
    7086         322 :     i_relowner = PQfnumber(res, "relowner");
    7087         322 :     i_relchecks = PQfnumber(res, "relchecks");
    7088         322 :     i_relhasindex = PQfnumber(res, "relhasindex");
    7089         322 :     i_relhasrules = PQfnumber(res, "relhasrules");
    7090         322 :     i_relpages = PQfnumber(res, "relpages");
    7091         322 :     i_toastpages = PQfnumber(res, "toastpages");
    7092         322 :     i_owning_tab = PQfnumber(res, "owning_tab");
    7093         322 :     i_owning_col = PQfnumber(res, "owning_col");
    7094         322 :     i_reltablespace = PQfnumber(res, "reltablespace");
    7095         322 :     i_relhasoids = PQfnumber(res, "relhasoids");
    7096         322 :     i_relhastriggers = PQfnumber(res, "relhastriggers");
    7097         322 :     i_relpersistence = PQfnumber(res, "relpersistence");
    7098         322 :     i_relispopulated = PQfnumber(res, "relispopulated");
    7099         322 :     i_relreplident = PQfnumber(res, "relreplident");
    7100         322 :     i_relrowsec = PQfnumber(res, "relrowsecurity");
    7101         322 :     i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
    7102         322 :     i_relfrozenxid = PQfnumber(res, "relfrozenxid");
    7103         322 :     i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
    7104         322 :     i_toastoid = PQfnumber(res, "toid");
    7105         322 :     i_relminmxid = PQfnumber(res, "relminmxid");
    7106         322 :     i_toastminmxid = PQfnumber(res, "tminmxid");
    7107         322 :     i_reloptions = PQfnumber(res, "reloptions");
    7108         322 :     i_checkoption = PQfnumber(res, "checkoption");
    7109         322 :     i_toastreloptions = PQfnumber(res, "toast_reloptions");
    7110         322 :     i_reloftype = PQfnumber(res, "reloftype");
    7111         322 :     i_foreignserver = PQfnumber(res, "foreignserver");
    7112         322 :     i_amname = PQfnumber(res, "amname");
    7113         322 :     i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
    7114         322 :     i_relacl = PQfnumber(res, "relacl");
    7115         322 :     i_acldefault = PQfnumber(res, "acldefault");
    7116         322 :     i_ispartition = PQfnumber(res, "ispartition");
    7117             : 
    7118         322 :     if (dopt->lockWaitTimeout)
    7119             :     {
    7120             :         /*
    7121             :          * Arrange to fail instead of waiting forever for a table lock.
    7122             :          *
    7123             :          * NB: this coding assumes that the only queries issued within the
    7124             :          * following loop are LOCK TABLEs; else the timeout may be undesirably
    7125             :          * applied to other things too.
    7126             :          */
    7127           4 :         resetPQExpBuffer(query);
    7128           4 :         appendPQExpBufferStr(query, "SET statement_timeout = ");
    7129           4 :         appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
    7130           4 :         ExecuteSqlStatement(fout, query->data);
    7131             :     }
    7132             : 
    7133         322 :     resetPQExpBuffer(query);
    7134             : 
    7135       85584 :     for (i = 0; i < ntups; i++)
    7136             :     {
    7137       85262 :         tblinfo[i].dobj.objType = DO_TABLE;
    7138       85262 :         tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
    7139       85262 :         tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
    7140       85262 :         AssignDumpId(&tblinfo[i].dobj);
    7141       85262 :         tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
    7142      170524 :         tblinfo[i].dobj.namespace =
    7143       85262 :             findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
    7144       85262 :         tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
    7145       85262 :         tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    7146       85262 :         tblinfo[i].dacl.privtype = 0;
    7147       85262 :         tblinfo[i].dacl.initprivs = NULL;
    7148       85262 :         tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
    7149       85262 :         tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
    7150       85262 :         tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
    7151       85262 :         tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
    7152       85262 :         tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
    7153       85262 :         tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
    7154       85262 :         tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
    7155       85262 :         if (PQgetisnull(res, i, i_toastpages))
    7156       67424 :             tblinfo[i].toastpages = 0;
    7157             :         else
    7158       17838 :             tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
    7159       85262 :         if (PQgetisnull(res, i, i_owning_tab))
    7160             :         {
    7161       84420 :             tblinfo[i].owning_tab = InvalidOid;
    7162       84420 :             tblinfo[i].owning_col = 0;
    7163             :         }
    7164             :         else
    7165             :         {
    7166         842 :             tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
    7167         842 :             tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
    7168             :         }
    7169       85262 :         tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
    7170       85262 :         tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
    7171       85262 :         tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
    7172       85262 :         tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
    7173       85262 :         tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
    7174       85262 :         tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
    7175       85262 :         tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
    7176       85262 :         tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
    7177       85262 :         tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
    7178       85262 :         tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
    7179       85262 :         tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
    7180       85262 :         tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
    7181       85262 :         tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
    7182       85262 :         tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
    7183       85262 :         if (PQgetisnull(res, i, i_checkoption))
    7184       85166 :             tblinfo[i].checkoption = NULL;
    7185             :         else
    7186          96 :             tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
    7187       85262 :         tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
    7188       85262 :         tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
    7189       85262 :         tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
    7190       85262 :         if (PQgetisnull(res, i, i_amname))
    7191       49976 :             tblinfo[i].amname = NULL;
    7192             :         else
    7193       35286 :             tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
    7194       85262 :         tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
    7195       85262 :         tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
    7196             : 
    7197             :         /* other fields were zeroed above */
    7198             : 
    7199             :         /*
    7200             :          * Decide whether we want to dump this table.
    7201             :          */
    7202       85262 :         if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
    7203         370 :             tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
    7204             :         else
    7205       84892 :             selectDumpableTable(&tblinfo[i], fout);
    7206             : 
    7207             :         /*
    7208             :          * Now, consider the table "interesting" if we need to dump its
    7209             :          * definition, data or its statistics.  Later on, we'll skip a lot of
    7210             :          * data collection for uninteresting tables.
    7211             :          *
    7212             :          * Note: the "interesting" flag will also be set by flagInhTables for
    7213             :          * parents of interesting tables, so that we collect necessary
    7214             :          * inheritance info even when the parents are not themselves being
    7215             :          * dumped.  This is the main reason why we need an "interesting" flag
    7216             :          * that's separate from the components-to-dump bitmask.
    7217             :          */
    7218       85262 :         tblinfo[i].interesting = (tblinfo[i].dobj.dump &
    7219             :                                   (DUMP_COMPONENT_DEFINITION |
    7220             :                                    DUMP_COMPONENT_DATA |
    7221       85262 :                                    DUMP_COMPONENT_STATISTICS)) != 0;
    7222             : 
    7223       85262 :         tblinfo[i].dummy_view = false;  /* might get set during sort */
    7224       85262 :         tblinfo[i].postponed_def = false;   /* might get set during sort */
    7225             : 
    7226             :         /* Tables have data */
    7227       85262 :         tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
    7228             : 
    7229             :         /* Mark whether table has an ACL */
    7230       85262 :         if (!PQgetisnull(res, i, i_relacl))
    7231       66848 :             tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    7232       85262 :         tblinfo[i].hascolumnACLs = false;   /* may get set later */
    7233             : 
    7234             :         /* Add statistics */
    7235       85262 :         if (tblinfo[i].interesting)
    7236       13310 :             getRelationStatistics(fout, &tblinfo[i].dobj, tblinfo[i].relkind);
    7237             : 
    7238             :         /*
    7239             :          * Read-lock target tables to make sure they aren't DROPPED or altered
    7240             :          * in schema before we get around to dumping them.
    7241             :          *
    7242             :          * Note that we don't explicitly lock parents of the target tables; we
    7243             :          * assume our lock on the child is enough to prevent schema
    7244             :          * alterations to parent tables.
    7245             :          *
    7246             :          * NOTE: it'd be kinda nice to lock other relations too, not only
    7247             :          * plain or partitioned tables, but the backend doesn't presently
    7248             :          * allow that.
    7249             :          *
    7250             :          * We only need to lock the table for certain components; see
    7251             :          * pg_dump.h
    7252             :          */
    7253       85262 :         if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
    7254       13310 :             (tblinfo[i].relkind == RELKIND_RELATION ||
    7255        3924 :              tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
    7256             :         {
    7257             :             /*
    7258             :              * Tables are locked in batches.  When dumping from a remote
    7259             :              * server this can save a significant amount of time by reducing
    7260             :              * the number of round trips.
    7261             :              */
    7262       10480 :             if (query->len == 0)
    7263         206 :                 appendPQExpBuffer(query, "LOCK TABLE %s",
    7264         206 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7265             :             else
    7266             :             {
    7267       10274 :                 appendPQExpBuffer(query, ", %s",
    7268       10274 :                                   fmtQualifiedDumpable(&tblinfo[i]));
    7269             : 
    7270             :                 /* Arbitrarily end a batch when query length reaches 100K. */
    7271       10274 :                 if (query->len >= 100000)
    7272             :                 {
    7273             :                     /* Lock another batch of tables. */
    7274           0 :                     appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7275           0 :                     ExecuteSqlStatement(fout, query->data);
    7276           0 :                     resetPQExpBuffer(query);
    7277             :                 }
    7278             :             }
    7279             :         }
    7280             :     }
    7281             : 
    7282         322 :     if (query->len != 0)
    7283             :     {
    7284             :         /* Lock the tables in the last batch. */
    7285         206 :         appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
    7286         206 :         ExecuteSqlStatement(fout, query->data);
    7287             :     }
    7288             : 
    7289         320 :     if (dopt->lockWaitTimeout)
    7290             :     {
    7291           4 :         ExecuteSqlStatement(fout, "SET statement_timeout = 0");
    7292             :     }
    7293             : 
    7294         320 :     PQclear(res);
    7295             : 
    7296         320 :     destroyPQExpBuffer(query);
    7297             : 
    7298         320 :     return tblinfo;
    7299             : }
    7300             : 
    7301             : /*
    7302             :  * getOwnedSeqs
    7303             :  *    identify owned sequences and mark them as dumpable if owning table is
    7304             :  *
    7305             :  * We used to do this in getTables(), but it's better to do it after the
    7306             :  * index used by findTableByOid() has been set up.
    7307             :  */
    7308             : void
    7309         320 : getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
    7310             : {
    7311             :     int         i;
    7312             : 
    7313             :     /*
    7314             :      * Force sequences that are "owned" by table columns to be dumped whenever
    7315             :      * their owning table is being dumped.
    7316             :      */
    7317       85060 :     for (i = 0; i < numTables; i++)
    7318             :     {
    7319       84740 :         TableInfo  *seqinfo = &tblinfo[i];
    7320             :         TableInfo  *owning_tab;
    7321             : 
    7322       84740 :         if (!OidIsValid(seqinfo->owning_tab))
    7323       83904 :             continue;           /* not an owned sequence */
    7324             : 
    7325         836 :         owning_tab = findTableByOid(seqinfo->owning_tab);
    7326         836 :         if (owning_tab == NULL)
    7327           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
    7328             :                      seqinfo->owning_tab, seqinfo->dobj.catId.oid);
    7329             : 
    7330             :         /*
    7331             :          * For an identity sequence, dump exactly the same components for the
    7332             :          * sequence as for the owning table.  This is important because we
    7333             :          * treat the identity sequence as an integral part of the table.  For
    7334             :          * example, there is not any DDL command that allows creation of such
    7335             :          * a sequence independently of the table.
    7336             :          *
    7337             :          * For other owned sequences such as serial sequences, we need to dump
    7338             :          * the components that are being dumped for the table and any
    7339             :          * components that the sequence is explicitly marked with.
    7340             :          *
    7341             :          * We can't simply use the set of components which are being dumped
    7342             :          * for the table as the table might be in an extension (and only the
    7343             :          * non-extension components, eg: ACLs if changed, security labels, and
    7344             :          * policies, are being dumped) while the sequence is not (and
    7345             :          * therefore the definition and other components should also be
    7346             :          * dumped).
    7347             :          *
    7348             :          * If the sequence is part of the extension then it should be properly
    7349             :          * marked by checkExtensionMembership() and this will be a no-op as
    7350             :          * the table will be equivalently marked.
    7351             :          */
    7352         836 :         if (seqinfo->is_identity_sequence)
    7353         402 :             seqinfo->dobj.dump = owning_tab->dobj.dump;
    7354             :         else
    7355         434 :             seqinfo->dobj.dump |= owning_tab->dobj.dump;
    7356             : 
    7357             :         /* Make sure that necessary data is available if we're dumping it */
    7358         836 :         if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
    7359             :         {
    7360         644 :             seqinfo->interesting = true;
    7361         644 :             owning_tab->interesting = true;
    7362             :         }
    7363             :     }
    7364         320 : }
    7365             : 
    7366             : /*
    7367             :  * getInherits
    7368             :  *    read all the inheritance information
    7369             :  * from the system catalogs return them in the InhInfo* structure
    7370             :  *
    7371             :  * numInherits is set to the number of pairs read in
    7372             :  */
    7373             : InhInfo *
    7374         320 : getInherits(Archive *fout, int *numInherits)
    7375             : {
    7376             :     PGresult   *res;
    7377             :     int         ntups;
    7378             :     int         i;
    7379         320 :     PQExpBuffer query = createPQExpBuffer();
    7380             :     InhInfo    *inhinfo;
    7381             : 
    7382             :     int         i_inhrelid;
    7383             :     int         i_inhparent;
    7384             : 
    7385             :     /* find all the inheritance information */
    7386         320 :     appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
    7387             : 
    7388         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7389             : 
    7390         320 :     ntups = PQntuples(res);
    7391             : 
    7392         320 :     *numInherits = ntups;
    7393             : 
    7394         320 :     inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
    7395             : 
    7396         320 :     i_inhrelid = PQfnumber(res, "inhrelid");
    7397         320 :     i_inhparent = PQfnumber(res, "inhparent");
    7398             : 
    7399        6392 :     for (i = 0; i < ntups; i++)
    7400             :     {
    7401        6072 :         inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
    7402        6072 :         inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
    7403             :     }
    7404             : 
    7405         320 :     PQclear(res);
    7406             : 
    7407         320 :     destroyPQExpBuffer(query);
    7408             : 
    7409         320 :     return inhinfo;
    7410             : }
    7411             : 
    7412             : /*
    7413             :  * getPartitioningInfo
    7414             :  *    get information about partitioning
    7415             :  *
    7416             :  * For the most part, we only collect partitioning info about tables we
    7417             :  * intend to dump.  However, this function has to consider all partitioned
    7418             :  * tables in the database, because we need to know about parents of partitions
    7419             :  * we are going to dump even if the parents themselves won't be dumped.
    7420             :  *
    7421             :  * Specifically, what we need to know is whether each partitioned table
    7422             :  * has an "unsafe" partitioning scheme that requires us to force
    7423             :  * load-via-partition-root mode for its children.  Currently the only case
    7424             :  * for which we force that is hash partitioning on enum columns, since the
    7425             :  * hash codes depend on enum value OIDs which won't be replicated across
    7426             :  * dump-and-reload.  There are other cases in which load-via-partition-root
    7427             :  * might be necessary, but we expect users to cope with them.
    7428             :  */
    7429             : void
    7430         320 : getPartitioningInfo(Archive *fout)
    7431             : {
    7432             :     PQExpBuffer query;
    7433             :     PGresult   *res;
    7434             :     int         ntups;
    7435             : 
    7436             :     /* hash partitioning didn't exist before v11 */
    7437         320 :     if (fout->remoteVersion < 110000)
    7438           0 :         return;
    7439             :     /* needn't bother if not dumping data */
    7440         320 :     if (!fout->dopt->dumpData)
    7441          40 :         return;
    7442             : 
    7443         280 :     query = createPQExpBuffer();
    7444             : 
    7445             :     /*
    7446             :      * Unsafe partitioning schemes are exactly those for which hash enum_ops
    7447             :      * appears among the partition opclasses.  We needn't check partstrat.
    7448             :      *
    7449             :      * Note that this query may well retrieve info about tables we aren't
    7450             :      * going to dump and hence have no lock on.  That's okay since we need not
    7451             :      * invoke any unsafe server-side functions.
    7452             :      */
    7453         280 :     appendPQExpBufferStr(query,
    7454             :                          "SELECT partrelid FROM pg_partitioned_table WHERE\n"
    7455             :                          "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
    7456             :                          "ON c.opcmethod = a.oid\n"
    7457             :                          "WHERE opcname = 'enum_ops' "
    7458             :                          "AND opcnamespace = 'pg_catalog'::regnamespace "
    7459             :                          "AND amname = 'hash') = ANY(partclass)");
    7460             : 
    7461         280 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7462             : 
    7463         280 :     ntups = PQntuples(res);
    7464             : 
    7465         284 :     for (int i = 0; i < ntups; i++)
    7466             :     {
    7467           4 :         Oid         tabrelid = atooid(PQgetvalue(res, i, 0));
    7468             :         TableInfo  *tbinfo;
    7469             : 
    7470           4 :         tbinfo = findTableByOid(tabrelid);
    7471           4 :         if (tbinfo == NULL)
    7472           0 :             pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
    7473             :                      tabrelid);
    7474           4 :         tbinfo->unsafe_partitions = true;
    7475             :     }
    7476             : 
    7477         280 :     PQclear(res);
    7478             : 
    7479         280 :     destroyPQExpBuffer(query);
    7480             : }
    7481             : 
    7482             : /*
    7483             :  * getIndexes
    7484             :  *    get information about every index on a dumpable table
    7485             :  *
    7486             :  * Note: index data is not returned directly to the caller, but it
    7487             :  * does get entered into the DumpableObject tables.
    7488             :  */
    7489             : void
    7490         320 : getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
    7491             : {
    7492         320 :     PQExpBuffer query = createPQExpBuffer();
    7493         320 :     PQExpBuffer tbloids = createPQExpBuffer();
    7494             :     PGresult   *res;
    7495             :     int         ntups;
    7496             :     int         curtblindx;
    7497             :     IndxInfo   *indxinfo;
    7498             :     int         i_tableoid,
    7499             :                 i_oid,
    7500             :                 i_indrelid,
    7501             :                 i_indexname,
    7502             :                 i_parentidx,
    7503             :                 i_indexdef,
    7504             :                 i_indnkeyatts,
    7505             :                 i_indnatts,
    7506             :                 i_indkey,
    7507             :                 i_indisclustered,
    7508             :                 i_indisreplident,
    7509             :                 i_indnullsnotdistinct,
    7510             :                 i_contype,
    7511             :                 i_conname,
    7512             :                 i_condeferrable,
    7513             :                 i_condeferred,
    7514             :                 i_conperiod,
    7515             :                 i_contableoid,
    7516             :                 i_conoid,
    7517             :                 i_condef,
    7518             :                 i_tablespace,
    7519             :                 i_indreloptions,
    7520             :                 i_indstatcols,
    7521             :                 i_indstatvals;
    7522             : 
    7523             :     /*
    7524             :      * We want to perform just one query against pg_index.  However, we
    7525             :      * mustn't try to select every row of the catalog and then sort it out on
    7526             :      * the client side, because some of the server-side functions we need
    7527             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7528             :      * build an array of the OIDs of tables we care about (and now have lock
    7529             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7530             :      */
    7531         320 :     appendPQExpBufferChar(tbloids, '{');
    7532       85060 :     for (int i = 0; i < numTables; i++)
    7533             :     {
    7534       84740 :         TableInfo  *tbinfo = &tblinfo[i];
    7535             : 
    7536       84740 :         if (!tbinfo->hasindex)
    7537       59552 :             continue;
    7538             : 
    7539             :         /*
    7540             :          * We can ignore indexes of uninteresting tables.
    7541             :          */
    7542       25188 :         if (!tbinfo->interesting)
    7543       21222 :             continue;
    7544             : 
    7545             :         /* OK, we need info for this table */
    7546        3966 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7547        3806 :             appendPQExpBufferChar(tbloids, ',');
    7548        3966 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    7549             :     }
    7550         320 :     appendPQExpBufferChar(tbloids, '}');
    7551             : 
    7552         320 :     appendPQExpBufferStr(query,
    7553             :                          "SELECT t.tableoid, t.oid, i.indrelid, "
    7554             :                          "t.relname AS indexname, "
    7555             :                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
    7556             :                          "i.indkey, i.indisclustered, "
    7557             :                          "c.contype, c.conname, "
    7558             :                          "c.condeferrable, c.condeferred, "
    7559             :                          "c.tableoid AS contableoid, "
    7560             :                          "c.oid AS conoid, "
    7561             :                          "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
    7562             :                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
    7563             :                          "t.reloptions AS indreloptions, ");
    7564             : 
    7565             : 
    7566         320 :     if (fout->remoteVersion >= 90400)
    7567         320 :         appendPQExpBufferStr(query,
    7568             :                              "i.indisreplident, ");
    7569             :     else
    7570           0 :         appendPQExpBufferStr(query,
    7571             :                              "false AS indisreplident, ");
    7572             : 
    7573         320 :     if (fout->remoteVersion >= 110000)
    7574         320 :         appendPQExpBufferStr(query,
    7575             :                              "inh.inhparent AS parentidx, "
    7576             :                              "i.indnkeyatts AS indnkeyatts, "
    7577             :                              "i.indnatts AS indnatts, "
    7578             :                              "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
    7579             :                              "  FROM pg_catalog.pg_attribute "
    7580             :                              "  WHERE attrelid = i.indexrelid AND "
    7581             :                              "    attstattarget >= 0) AS indstatcols, "
    7582             :                              "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
    7583             :                              "  FROM pg_catalog.pg_attribute "
    7584             :                              "  WHERE attrelid = i.indexrelid AND "
    7585             :                              "    attstattarget >= 0) AS indstatvals, ");
    7586             :     else
    7587           0 :         appendPQExpBufferStr(query,
    7588             :                              "0 AS parentidx, "
    7589             :                              "i.indnatts AS indnkeyatts, "
    7590             :                              "i.indnatts AS indnatts, "
    7591             :                              "'' AS indstatcols, "
    7592             :                              "'' AS indstatvals, ");
    7593             : 
    7594         320 :     if (fout->remoteVersion >= 150000)
    7595         320 :         appendPQExpBufferStr(query,
    7596             :                              "i.indnullsnotdistinct, ");
    7597             :     else
    7598           0 :         appendPQExpBufferStr(query,
    7599             :                              "false AS indnullsnotdistinct, ");
    7600             : 
    7601         320 :     if (fout->remoteVersion >= 180000)
    7602         320 :         appendPQExpBufferStr(query,
    7603             :                              "c.conperiod ");
    7604             :     else
    7605           0 :         appendPQExpBufferStr(query,
    7606             :                              "NULL AS conperiod ");
    7607             : 
    7608             :     /*
    7609             :      * The point of the messy-looking outer join is to find a constraint that
    7610             :      * is related by an internal dependency link to the index. If we find one,
    7611             :      * create a CONSTRAINT entry linked to the INDEX entry.  We assume an
    7612             :      * index won't have more than one internal dependency.
    7613             :      *
    7614             :      * Note: the check on conrelid is redundant, but useful because that
    7615             :      * column is indexed while conindid is not.
    7616             :      */
    7617         320 :     if (fout->remoteVersion >= 110000)
    7618             :     {
    7619         320 :         appendPQExpBuffer(query,
    7620             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7621             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7622             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7623             :                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
    7624             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7625             :                           "ON (i.indrelid = c.conrelid AND "
    7626             :                           "i.indexrelid = c.conindid AND "
    7627             :                           "c.contype IN ('p','u','x')) "
    7628             :                           "LEFT JOIN pg_catalog.pg_inherits inh "
    7629             :                           "ON (inh.inhrelid = indexrelid) "
    7630             :                           "WHERE (i.indisvalid OR t2.relkind = 'p') "
    7631             :                           "AND i.indisready "
    7632             :                           "ORDER BY i.indrelid, indexname",
    7633             :                           tbloids->data);
    7634             :     }
    7635             :     else
    7636             :     {
    7637             :         /*
    7638             :          * the test on indisready is necessary in 9.2, and harmless in
    7639             :          * earlier/later versions
    7640             :          */
    7641           0 :         appendPQExpBuffer(query,
    7642             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7643             :                           "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
    7644             :                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
    7645             :                           "LEFT JOIN pg_catalog.pg_constraint c "
    7646             :                           "ON (i.indrelid = c.conrelid AND "
    7647             :                           "i.indexrelid = c.conindid AND "
    7648             :                           "c.contype IN ('p','u','x')) "
    7649             :                           "WHERE i.indisvalid AND i.indisready "
    7650             :                           "ORDER BY i.indrelid, indexname",
    7651             :                           tbloids->data);
    7652             :     }
    7653             : 
    7654         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7655             : 
    7656         320 :     ntups = PQntuples(res);
    7657             : 
    7658         320 :     i_tableoid = PQfnumber(res, "tableoid");
    7659         320 :     i_oid = PQfnumber(res, "oid");
    7660         320 :     i_indrelid = PQfnumber(res, "indrelid");
    7661         320 :     i_indexname = PQfnumber(res, "indexname");
    7662         320 :     i_parentidx = PQfnumber(res, "parentidx");
    7663         320 :     i_indexdef = PQfnumber(res, "indexdef");
    7664         320 :     i_indnkeyatts = PQfnumber(res, "indnkeyatts");
    7665         320 :     i_indnatts = PQfnumber(res, "indnatts");
    7666         320 :     i_indkey = PQfnumber(res, "indkey");
    7667         320 :     i_indisclustered = PQfnumber(res, "indisclustered");
    7668         320 :     i_indisreplident = PQfnumber(res, "indisreplident");
    7669         320 :     i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
    7670         320 :     i_contype = PQfnumber(res, "contype");
    7671         320 :     i_conname = PQfnumber(res, "conname");
    7672         320 :     i_condeferrable = PQfnumber(res, "condeferrable");
    7673         320 :     i_condeferred = PQfnumber(res, "condeferred");
    7674         320 :     i_conperiod = PQfnumber(res, "conperiod");
    7675         320 :     i_contableoid = PQfnumber(res, "contableoid");
    7676         320 :     i_conoid = PQfnumber(res, "conoid");
    7677         320 :     i_condef = PQfnumber(res, "condef");
    7678         320 :     i_tablespace = PQfnumber(res, "tablespace");
    7679         320 :     i_indreloptions = PQfnumber(res, "indreloptions");
    7680         320 :     i_indstatcols = PQfnumber(res, "indstatcols");
    7681         320 :     i_indstatvals = PQfnumber(res, "indstatvals");
    7682             : 
    7683         320 :     indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
    7684             : 
    7685             :     /*
    7686             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    7687             :      * j is handled by the inner loop.
    7688             :      */
    7689         320 :     curtblindx = -1;
    7690        4278 :     for (int j = 0; j < ntups;)
    7691             :     {
    7692        3958 :         Oid         indrelid = atooid(PQgetvalue(res, j, i_indrelid));
    7693        3958 :         TableInfo  *tbinfo = NULL;
    7694             :         int         numinds;
    7695             : 
    7696             :         /* Count rows for this table */
    7697        5202 :         for (numinds = 1; numinds < ntups - j; numinds++)
    7698        5042 :             if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
    7699        3798 :                 break;
    7700             : 
    7701             :         /*
    7702             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7703             :          * order.
    7704             :          */
    7705       45896 :         while (++curtblindx < numTables)
    7706             :         {
    7707       45896 :             tbinfo = &tblinfo[curtblindx];
    7708       45896 :             if (tbinfo->dobj.catId.oid == indrelid)
    7709        3958 :                 break;
    7710             :         }
    7711        3958 :         if (curtblindx >= numTables)
    7712           0 :             pg_fatal("unrecognized table OID %u", indrelid);
    7713             :         /* cross-check that we only got requested tables */
    7714        3958 :         if (!tbinfo->hasindex ||
    7715        3958 :             !tbinfo->interesting)
    7716           0 :             pg_fatal("unexpected index data for table \"%s\"",
    7717             :                      tbinfo->dobj.name);
    7718             : 
    7719             :         /* Save data for this table */
    7720        3958 :         tbinfo->indexes = indxinfo + j;
    7721        3958 :         tbinfo->numIndexes = numinds;
    7722             : 
    7723        9160 :         for (int c = 0; c < numinds; c++, j++)
    7724             :         {
    7725             :             char        contype;
    7726             :             char        indexkind;
    7727             :             RelStatsInfo *relstats;
    7728             : 
    7729        5202 :             indxinfo[j].dobj.objType = DO_INDEX;
    7730        5202 :             indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    7731        5202 :             indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    7732        5202 :             AssignDumpId(&indxinfo[j].dobj);
    7733        5202 :             indxinfo[j].dobj.dump = tbinfo->dobj.dump;
    7734        5202 :             indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
    7735        5202 :             indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    7736        5202 :             indxinfo[j].indextable = tbinfo;
    7737        5202 :             indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
    7738        5202 :             indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
    7739        5202 :             indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
    7740        5202 :             indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
    7741        5202 :             indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
    7742        5202 :             indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
    7743        5202 :             indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
    7744        5202 :             indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
    7745        5202 :             parseOidArray(PQgetvalue(res, j, i_indkey),
    7746        5202 :                           indxinfo[j].indkeys, indxinfo[j].indnattrs);
    7747        5202 :             indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
    7748        5202 :             indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
    7749        5202 :             indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
    7750        5202 :             indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
    7751        5202 :             indxinfo[j].partattaches = (SimplePtrList)
    7752             :             {
    7753             :                 NULL, NULL
    7754             :             };
    7755             : 
    7756        5202 :             if (indxinfo[j].parentidx == 0)
    7757        4042 :                 indexkind = RELKIND_INDEX;
    7758             :             else
    7759        1160 :                 indexkind = RELKIND_PARTITIONED_INDEX;
    7760             : 
    7761        5202 :             contype = *(PQgetvalue(res, j, i_contype));
    7762        5202 :             relstats = getRelationStatistics(fout, &indxinfo[j].dobj, indexkind);
    7763             : 
    7764        5202 :             if (contype == 'p' || contype == 'u' || contype == 'x')
    7765        3020 :             {
    7766             :                 /*
    7767             :                  * If we found a constraint matching the index, create an
    7768             :                  * entry for it.
    7769             :                  */
    7770             :                 ConstraintInfo *constrinfo;
    7771             : 
    7772        3020 :                 constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
    7773        3020 :                 constrinfo->dobj.objType = DO_CONSTRAINT;
    7774        3020 :                 constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    7775        3020 :                 constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    7776        3020 :                 AssignDumpId(&constrinfo->dobj);
    7777        3020 :                 constrinfo->dobj.dump = tbinfo->dobj.dump;
    7778        3020 :                 constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    7779        3020 :                 constrinfo->dobj.namespace = tbinfo->dobj.namespace;
    7780        3020 :                 constrinfo->contable = tbinfo;
    7781        3020 :                 constrinfo->condomain = NULL;
    7782        3020 :                 constrinfo->contype = contype;
    7783        3020 :                 if (contype == 'x')
    7784          20 :                     constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
    7785             :                 else
    7786        3000 :                     constrinfo->condef = NULL;
    7787        3020 :                 constrinfo->confrelid = InvalidOid;
    7788        3020 :                 constrinfo->conindex = indxinfo[j].dobj.dumpId;
    7789        3020 :                 constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
    7790        3020 :                 constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
    7791        3020 :                 constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
    7792        3020 :                 constrinfo->conislocal = true;
    7793        3020 :                 constrinfo->separate = true;
    7794             : 
    7795        3020 :                 indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
    7796        3020 :                 if (relstats != NULL)
    7797        2372 :                     addObjectDependency(&relstats->dobj, constrinfo->dobj.dumpId);
    7798             :             }
    7799             :             else
    7800             :             {
    7801             :                 /* Plain secondary index */
    7802        2182 :                 indxinfo[j].indexconstraint = 0;
    7803             :             }
    7804             :         }
    7805             :     }
    7806             : 
    7807         320 :     PQclear(res);
    7808             : 
    7809         320 :     destroyPQExpBuffer(query);
    7810         320 :     destroyPQExpBuffer(tbloids);
    7811         320 : }
    7812             : 
    7813             : /*
    7814             :  * getExtendedStatistics
    7815             :  *    get information about extended-statistics objects.
    7816             :  *
    7817             :  * Note: extended statistics data is not returned directly to the caller, but
    7818             :  * it does get entered into the DumpableObject tables.
    7819             :  */
    7820             : void
    7821         320 : getExtendedStatistics(Archive *fout)
    7822             : {
    7823             :     PQExpBuffer query;
    7824             :     PGresult   *res;
    7825             :     StatsExtInfo *statsextinfo;
    7826             :     int         ntups;
    7827             :     int         i_tableoid;
    7828             :     int         i_oid;
    7829             :     int         i_stxname;
    7830             :     int         i_stxnamespace;
    7831             :     int         i_stxowner;
    7832             :     int         i_stxrelid;
    7833             :     int         i_stattarget;
    7834             :     int         i;
    7835             : 
    7836             :     /* Extended statistics were new in v10 */
    7837         320 :     if (fout->remoteVersion < 100000)
    7838           0 :         return;
    7839             : 
    7840         320 :     query = createPQExpBuffer();
    7841             : 
    7842         320 :     if (fout->remoteVersion < 130000)
    7843           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    7844             :                              "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
    7845             :                              "FROM pg_catalog.pg_statistic_ext");
    7846             :     else
    7847         320 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
    7848             :                              "stxnamespace, stxowner, stxrelid, stxstattarget "
    7849             :                              "FROM pg_catalog.pg_statistic_ext");
    7850             : 
    7851         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7852             : 
    7853         320 :     ntups = PQntuples(res);
    7854             : 
    7855         320 :     i_tableoid = PQfnumber(res, "tableoid");
    7856         320 :     i_oid = PQfnumber(res, "oid");
    7857         320 :     i_stxname = PQfnumber(res, "stxname");
    7858         320 :     i_stxnamespace = PQfnumber(res, "stxnamespace");
    7859         320 :     i_stxowner = PQfnumber(res, "stxowner");
    7860         320 :     i_stxrelid = PQfnumber(res, "stxrelid");
    7861         320 :     i_stattarget = PQfnumber(res, "stxstattarget");
    7862             : 
    7863         320 :     statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
    7864             : 
    7865         658 :     for (i = 0; i < ntups; i++)
    7866             :     {
    7867         338 :         statsextinfo[i].dobj.objType = DO_STATSEXT;
    7868         338 :         statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    7869         338 :         statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    7870         338 :         AssignDumpId(&statsextinfo[i].dobj);
    7871         338 :         statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
    7872         676 :         statsextinfo[i].dobj.namespace =
    7873         338 :             findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
    7874         338 :         statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
    7875         676 :         statsextinfo[i].stattable =
    7876         338 :             findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
    7877         338 :         if (PQgetisnull(res, i, i_stattarget))
    7878         244 :             statsextinfo[i].stattarget = -1;
    7879             :         else
    7880          94 :             statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
    7881             : 
    7882             :         /* Decide whether we want to dump it */
    7883         338 :         selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
    7884             :     }
    7885             : 
    7886         320 :     PQclear(res);
    7887         320 :     destroyPQExpBuffer(query);
    7888             : }
    7889             : 
    7890             : /*
    7891             :  * getConstraints
    7892             :  *
    7893             :  * Get info about constraints on dumpable tables.
    7894             :  *
    7895             :  * Currently handles foreign keys only.
    7896             :  * Unique and primary key constraints are handled with indexes,
    7897             :  * while check constraints are processed in getTableAttrs().
    7898             :  */
    7899             : void
    7900         320 : getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
    7901             : {
    7902         320 :     PQExpBuffer query = createPQExpBuffer();
    7903         320 :     PQExpBuffer tbloids = createPQExpBuffer();
    7904             :     PGresult   *res;
    7905             :     int         ntups;
    7906             :     int         curtblindx;
    7907         320 :     TableInfo  *tbinfo = NULL;
    7908             :     ConstraintInfo *constrinfo;
    7909             :     int         i_contableoid,
    7910             :                 i_conoid,
    7911             :                 i_conrelid,
    7912             :                 i_conname,
    7913             :                 i_confrelid,
    7914             :                 i_conindid,
    7915             :                 i_condef;
    7916             : 
    7917             :     /*
    7918             :      * We want to perform just one query against pg_constraint.  However, we
    7919             :      * mustn't try to select every row of the catalog and then sort it out on
    7920             :      * the client side, because some of the server-side functions we need
    7921             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    7922             :      * build an array of the OIDs of tables we care about (and now have lock
    7923             :      * on!), and use a WHERE clause to constrain which rows are selected.
    7924             :      */
    7925         320 :     appendPQExpBufferChar(tbloids, '{');
    7926       85060 :     for (int i = 0; i < numTables; i++)
    7927             :     {
    7928       84740 :         TableInfo  *tinfo = &tblinfo[i];
    7929             : 
    7930             :         /*
    7931             :          * For partitioned tables, foreign keys have no triggers so they must
    7932             :          * be included anyway in case some foreign keys are defined.
    7933             :          */
    7934       84740 :         if ((!tinfo->hastriggers &&
    7935       82472 :              tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
    7936        3242 :             !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    7937       82284 :             continue;
    7938             : 
    7939             :         /* OK, we need info for this table */
    7940        2456 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    7941        2346 :             appendPQExpBufferChar(tbloids, ',');
    7942        2456 :         appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
    7943             :     }
    7944         320 :     appendPQExpBufferChar(tbloids, '}');
    7945             : 
    7946         320 :     appendPQExpBufferStr(query,
    7947             :                          "SELECT c.tableoid, c.oid, "
    7948             :                          "conrelid, conname, confrelid, ");
    7949         320 :     if (fout->remoteVersion >= 110000)
    7950         320 :         appendPQExpBufferStr(query, "conindid, ");
    7951             :     else
    7952           0 :         appendPQExpBufferStr(query, "0 AS conindid, ");
    7953         320 :     appendPQExpBuffer(query,
    7954             :                       "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
    7955             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    7956             :                       "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    7957             :                       "WHERE contype = 'f' ",
    7958             :                       tbloids->data);
    7959         320 :     if (fout->remoteVersion >= 110000)
    7960         320 :         appendPQExpBufferStr(query,
    7961             :                              "AND conparentid = 0 ");
    7962         320 :     appendPQExpBufferStr(query,
    7963             :                          "ORDER BY conrelid, conname");
    7964             : 
    7965         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    7966             : 
    7967         320 :     ntups = PQntuples(res);
    7968             : 
    7969         320 :     i_contableoid = PQfnumber(res, "tableoid");
    7970         320 :     i_conoid = PQfnumber(res, "oid");
    7971         320 :     i_conrelid = PQfnumber(res, "conrelid");
    7972         320 :     i_conname = PQfnumber(res, "conname");
    7973         320 :     i_confrelid = PQfnumber(res, "confrelid");
    7974         320 :     i_conindid = PQfnumber(res, "conindid");
    7975         320 :     i_condef = PQfnumber(res, "condef");
    7976             : 
    7977         320 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    7978             : 
    7979         320 :     curtblindx = -1;
    7980         680 :     for (int j = 0; j < ntups; j++)
    7981             :     {
    7982         360 :         Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    7983             :         TableInfo  *reftable;
    7984             : 
    7985             :         /*
    7986             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    7987             :          * order.
    7988             :          */
    7989         360 :         if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
    7990             :         {
    7991       27470 :             while (++curtblindx < numTables)
    7992             :             {
    7993       27470 :                 tbinfo = &tblinfo[curtblindx];
    7994       27470 :                 if (tbinfo->dobj.catId.oid == conrelid)
    7995         340 :                     break;
    7996             :             }
    7997         340 :             if (curtblindx >= numTables)
    7998           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    7999             :         }
    8000             : 
    8001         360 :         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
    8002         360 :         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
    8003         360 :         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
    8004         360 :         AssignDumpId(&constrinfo[j].dobj);
    8005         360 :         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    8006         360 :         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8007         360 :         constrinfo[j].contable = tbinfo;
    8008         360 :         constrinfo[j].condomain = NULL;
    8009         360 :         constrinfo[j].contype = 'f';
    8010         360 :         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
    8011         360 :         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
    8012         360 :         constrinfo[j].conindex = 0;
    8013         360 :         constrinfo[j].condeferrable = false;
    8014         360 :         constrinfo[j].condeferred = false;
    8015         360 :         constrinfo[j].conislocal = true;
    8016         360 :         constrinfo[j].separate = true;
    8017             : 
    8018             :         /*
    8019             :          * Restoring an FK that points to a partitioned table requires that
    8020             :          * all partition indexes have been attached beforehand. Ensure that
    8021             :          * happens by making the constraint depend on each index partition
    8022             :          * attach object.
    8023             :          */
    8024         360 :         reftable = findTableByOid(constrinfo[j].confrelid);
    8025         360 :         if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
    8026             :         {
    8027          40 :             Oid         indexOid = atooid(PQgetvalue(res, j, i_conindid));
    8028             : 
    8029          40 :             if (indexOid != InvalidOid)
    8030             :             {
    8031          40 :                 for (int k = 0; k < reftable->numIndexes; k++)
    8032             :                 {
    8033             :                     IndxInfo   *refidx;
    8034             : 
    8035             :                     /* not our index? */
    8036          40 :                     if (reftable->indexes[k].dobj.catId.oid != indexOid)
    8037           0 :                         continue;
    8038             : 
    8039          40 :                     refidx = &reftable->indexes[k];
    8040          40 :                     addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
    8041          40 :                     break;
    8042             :                 }
    8043             :             }
    8044             :         }
    8045             :     }
    8046             : 
    8047         320 :     PQclear(res);
    8048             : 
    8049         320 :     destroyPQExpBuffer(query);
    8050         320 :     destroyPQExpBuffer(tbloids);
    8051         320 : }
    8052             : 
    8053             : /*
    8054             :  * addConstrChildIdxDeps
    8055             :  *
    8056             :  * Recursive subroutine for getConstraints
    8057             :  *
    8058             :  * Given an object representing a foreign key constraint and an index on the
    8059             :  * partitioned table it references, mark the constraint object as dependent
    8060             :  * on the DO_INDEX_ATTACH object of each index partition, recursively
    8061             :  * drilling down to their partitions if any.  This ensures that the FK is not
    8062             :  * restored until the index is fully marked valid.
    8063             :  */
    8064             : static void
    8065          90 : addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
    8066             : {
    8067             :     SimplePtrListCell *cell;
    8068             : 
    8069             :     Assert(dobj->objType == DO_FK_CONSTRAINT);
    8070             : 
    8071         310 :     for (cell = refidx->partattaches.head; cell; cell = cell->next)
    8072             :     {
    8073         220 :         IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
    8074             : 
    8075         220 :         addObjectDependency(dobj, attach->dobj.dumpId);
    8076             : 
    8077         220 :         if (attach->partitionIdx->partattaches.head != NULL)
    8078          50 :             addConstrChildIdxDeps(dobj, attach->partitionIdx);
    8079             :     }
    8080          90 : }
    8081             : 
    8082             : /*
    8083             :  * getDomainConstraints
    8084             :  *
    8085             :  * Get info about constraints on a domain.
    8086             :  */
    8087             : static void
    8088         290 : getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
    8089             : {
    8090             :     int         i;
    8091             :     ConstraintInfo *constrinfo;
    8092         290 :     PQExpBuffer query = createPQExpBuffer();
    8093             :     PGresult   *res;
    8094             :     int         i_tableoid,
    8095             :                 i_oid,
    8096             :                 i_conname,
    8097             :                 i_consrc;
    8098             :     int         ntups;
    8099             : 
    8100         290 :     if (!fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS])
    8101             :     {
    8102             :         /* Set up query for constraint-specific details */
    8103          90 :         appendPQExpBufferStr(query,
    8104             :                              "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
    8105             :                              "SELECT tableoid, oid, conname, "
    8106             :                              "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
    8107             :                              "convalidated "
    8108             :                              "FROM pg_catalog.pg_constraint "
    8109             :                              "WHERE contypid = $1 AND contype = 'c' "
    8110             :                              "ORDER BY conname");
    8111             : 
    8112          90 :         ExecuteSqlStatement(fout, query->data);
    8113             : 
    8114          90 :         fout->is_prepared[PREPQUERY_GETDOMAINCONSTRAINTS] = true;
    8115             :     }
    8116             : 
    8117         290 :     printfPQExpBuffer(query,
    8118             :                       "EXECUTE getDomainConstraints('%u')",
    8119             :                       tyinfo->dobj.catId.oid);
    8120             : 
    8121         290 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8122             : 
    8123         290 :     ntups = PQntuples(res);
    8124             : 
    8125         290 :     i_tableoid = PQfnumber(res, "tableoid");
    8126         290 :     i_oid = PQfnumber(res, "oid");
    8127         290 :     i_conname = PQfnumber(res, "conname");
    8128         290 :     i_consrc = PQfnumber(res, "consrc");
    8129             : 
    8130         290 :     constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
    8131             : 
    8132         290 :     tyinfo->nDomChecks = ntups;
    8133         290 :     tyinfo->domChecks = constrinfo;
    8134             : 
    8135         490 :     for (i = 0; i < ntups; i++)
    8136             :     {
    8137         200 :         bool        validated = PQgetvalue(res, i, 4)[0] == 't';
    8138             : 
    8139         200 :         constrinfo[i].dobj.objType = DO_CONSTRAINT;
    8140         200 :         constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8141         200 :         constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8142         200 :         AssignDumpId(&constrinfo[i].dobj);
    8143         200 :         constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
    8144         200 :         constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
    8145         200 :         constrinfo[i].contable = NULL;
    8146         200 :         constrinfo[i].condomain = tyinfo;
    8147         200 :         constrinfo[i].contype = 'c';
    8148         200 :         constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
    8149         200 :         constrinfo[i].confrelid = InvalidOid;
    8150         200 :         constrinfo[i].conindex = 0;
    8151         200 :         constrinfo[i].condeferrable = false;
    8152         200 :         constrinfo[i].condeferred = false;
    8153         200 :         constrinfo[i].conislocal = true;
    8154             : 
    8155         200 :         constrinfo[i].separate = !validated;
    8156             : 
    8157             :         /*
    8158             :          * Make the domain depend on the constraint, ensuring it won't be
    8159             :          * output till any constraint dependencies are OK.  If the constraint
    8160             :          * has not been validated, it's going to be dumped after the domain
    8161             :          * anyway, so this doesn't matter.
    8162             :          */
    8163         200 :         if (validated)
    8164         200 :             addObjectDependency(&tyinfo->dobj,
    8165         200 :                                 constrinfo[i].dobj.dumpId);
    8166             :     }
    8167             : 
    8168         290 :     PQclear(res);
    8169             : 
    8170         290 :     destroyPQExpBuffer(query);
    8171         290 : }
    8172             : 
    8173             : /*
    8174             :  * getRules
    8175             :  *    get basic information about every rule in the system
    8176             :  */
    8177             : void
    8178         320 : getRules(Archive *fout)
    8179             : {
    8180             :     PGresult   *res;
    8181             :     int         ntups;
    8182             :     int         i;
    8183         320 :     PQExpBuffer query = createPQExpBuffer();
    8184             :     RuleInfo   *ruleinfo;
    8185             :     int         i_tableoid;
    8186             :     int         i_oid;
    8187             :     int         i_rulename;
    8188             :     int         i_ruletable;
    8189             :     int         i_ev_type;
    8190             :     int         i_is_instead;
    8191             :     int         i_ev_enabled;
    8192             : 
    8193         320 :     appendPQExpBufferStr(query, "SELECT "
    8194             :                          "tableoid, oid, rulename, "
    8195             :                          "ev_class AS ruletable, ev_type, is_instead, "
    8196             :                          "ev_enabled "
    8197             :                          "FROM pg_rewrite "
    8198             :                          "ORDER BY oid");
    8199             : 
    8200         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8201             : 
    8202         320 :     ntups = PQntuples(res);
    8203             : 
    8204         320 :     ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
    8205             : 
    8206         320 :     i_tableoid = PQfnumber(res, "tableoid");
    8207         320 :     i_oid = PQfnumber(res, "oid");
    8208         320 :     i_rulename = PQfnumber(res, "rulename");
    8209         320 :     i_ruletable = PQfnumber(res, "ruletable");
    8210         320 :     i_ev_type = PQfnumber(res, "ev_type");
    8211         320 :     i_is_instead = PQfnumber(res, "is_instead");
    8212         320 :     i_ev_enabled = PQfnumber(res, "ev_enabled");
    8213             : 
    8214       49112 :     for (i = 0; i < ntups; i++)
    8215             :     {
    8216             :         Oid         ruletableoid;
    8217             : 
    8218       48792 :         ruleinfo[i].dobj.objType = DO_RULE;
    8219       48792 :         ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8220       48792 :         ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8221       48792 :         AssignDumpId(&ruleinfo[i].dobj);
    8222       48792 :         ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
    8223       48792 :         ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
    8224       48792 :         ruleinfo[i].ruletable = findTableByOid(ruletableoid);
    8225       48792 :         if (ruleinfo[i].ruletable == NULL)
    8226           0 :             pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
    8227             :                      ruletableoid, ruleinfo[i].dobj.catId.oid);
    8228       48792 :         ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
    8229       48792 :         ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
    8230       48792 :         ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
    8231       48792 :         ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
    8232       48792 :         ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
    8233       48792 :         if (ruleinfo[i].ruletable)
    8234             :         {
    8235             :             /*
    8236             :              * If the table is a view or materialized view, force its ON
    8237             :              * SELECT rule to be sorted before the view itself --- this
    8238             :              * ensures that any dependencies for the rule affect the table's
    8239             :              * positioning. Other rules are forced to appear after their
    8240             :              * table.
    8241             :              */
    8242       48792 :             if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
    8243        1514 :                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
    8244       48330 :                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
    8245             :             {
    8246       47606 :                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
    8247       47606 :                                     ruleinfo[i].dobj.dumpId);
    8248             :                 /* We'll merge the rule into CREATE VIEW, if possible */
    8249       47606 :                 ruleinfo[i].separate = false;
    8250             :             }
    8251             :             else
    8252             :             {
    8253        1186 :                 addObjectDependency(&ruleinfo[i].dobj,
    8254        1186 :                                     ruleinfo[i].ruletable->dobj.dumpId);
    8255        1186 :                 ruleinfo[i].separate = true;
    8256             :             }
    8257             :         }
    8258             :         else
    8259           0 :             ruleinfo[i].separate = true;
    8260             :     }
    8261             : 
    8262         320 :     PQclear(res);
    8263             : 
    8264         320 :     destroyPQExpBuffer(query);
    8265         320 : }
    8266             : 
    8267             : /*
    8268             :  * getTriggers
    8269             :  *    get information about every trigger on a dumpable table
    8270             :  *
    8271             :  * Note: trigger data is not returned directly to the caller, but it
    8272             :  * does get entered into the DumpableObject tables.
    8273             :  */
    8274             : void
    8275         320 : getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
    8276             : {
    8277         320 :     PQExpBuffer query = createPQExpBuffer();
    8278         320 :     PQExpBuffer tbloids = createPQExpBuffer();
    8279             :     PGresult   *res;
    8280             :     int         ntups;
    8281             :     int         curtblindx;
    8282             :     TriggerInfo *tginfo;
    8283             :     int         i_tableoid,
    8284             :                 i_oid,
    8285             :                 i_tgrelid,
    8286             :                 i_tgname,
    8287             :                 i_tgenabled,
    8288             :                 i_tgispartition,
    8289             :                 i_tgdef;
    8290             : 
    8291             :     /*
    8292             :      * We want to perform just one query against pg_trigger.  However, we
    8293             :      * mustn't try to select every row of the catalog and then sort it out on
    8294             :      * the client side, because some of the server-side functions we need
    8295             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8296             :      * build an array of the OIDs of tables we care about (and now have lock
    8297             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8298             :      */
    8299         320 :     appendPQExpBufferChar(tbloids, '{');
    8300       85060 :     for (int i = 0; i < numTables; i++)
    8301             :     {
    8302       84740 :         TableInfo  *tbinfo = &tblinfo[i];
    8303             : 
    8304       84740 :         if (!tbinfo->hastriggers ||
    8305        2268 :             !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
    8306       82996 :             continue;
    8307             : 
    8308             :         /* OK, we need info for this table */
    8309        1744 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8310        1638 :             appendPQExpBufferChar(tbloids, ',');
    8311        1744 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8312             :     }
    8313         320 :     appendPQExpBufferChar(tbloids, '}');
    8314             : 
    8315         320 :     if (fout->remoteVersion >= 150000)
    8316             :     {
    8317             :         /*
    8318             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8319             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8320             :          * under-parenthesization.
    8321             :          *
    8322             :          * NB: We need to see partition triggers in case the tgenabled flag
    8323             :          * has been changed from the parent.
    8324             :          */
    8325         320 :         appendPQExpBuffer(query,
    8326             :                           "SELECT t.tgrelid, t.tgname, "
    8327             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8328             :                           "t.tgenabled, t.tableoid, t.oid, "
    8329             :                           "t.tgparentid <> 0 AS tgispartition\n"
    8330             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8331             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8332             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8333             :                           "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
    8334             :                           "OR t.tgenabled != u.tgenabled) "
    8335             :                           "ORDER BY t.tgrelid, t.tgname",
    8336             :                           tbloids->data);
    8337             :     }
    8338           0 :     else if (fout->remoteVersion >= 130000)
    8339             :     {
    8340             :         /*
    8341             :          * NB: think not to use pretty=true in pg_get_triggerdef.  It could
    8342             :          * result in non-forward-compatible dumps of WHEN clauses due to
    8343             :          * under-parenthesization.
    8344             :          *
    8345             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8346             :          * tgenabled flag has been changed from the parent.
    8347             :          */
    8348           0 :         appendPQExpBuffer(query,
    8349             :                           "SELECT t.tgrelid, t.tgname, "
    8350             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8351             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
    8352             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8353             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8354             :                           "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
    8355             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
    8356             :                           "ORDER BY t.tgrelid, t.tgname",
    8357             :                           tbloids->data);
    8358             :     }
    8359           0 :     else if (fout->remoteVersion >= 110000)
    8360             :     {
    8361             :         /*
    8362             :          * NB: We need to see tgisinternal triggers in partitions, in case the
    8363             :          * tgenabled flag has been changed from the parent. No tgparentid in
    8364             :          * version 11-12, so we have to match them via pg_depend.
    8365             :          *
    8366             :          * See above about pretty=true in pg_get_triggerdef.
    8367             :          */
    8368           0 :         appendPQExpBuffer(query,
    8369             :                           "SELECT t.tgrelid, t.tgname, "
    8370             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8371             :                           "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
    8372             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8373             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8374             :                           "LEFT JOIN pg_catalog.pg_depend AS d ON "
    8375             :                           " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8376             :                           " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
    8377             :                           " d.objid = t.oid "
    8378             :                           "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
    8379             :                           "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
    8380             :                           "ORDER BY t.tgrelid, t.tgname",
    8381             :                           tbloids->data);
    8382             :     }
    8383             :     else
    8384             :     {
    8385             :         /* See above about pretty=true in pg_get_triggerdef */
    8386           0 :         appendPQExpBuffer(query,
    8387             :                           "SELECT t.tgrelid, t.tgname, "
    8388             :                           "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
    8389             :                           "t.tgenabled, false as tgispartition, "
    8390             :                           "t.tableoid, t.oid "
    8391             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8392             :                           "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
    8393             :                           "WHERE NOT tgisinternal "
    8394             :                           "ORDER BY t.tgrelid, t.tgname",
    8395             :                           tbloids->data);
    8396             :     }
    8397             : 
    8398         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8399             : 
    8400         320 :     ntups = PQntuples(res);
    8401             : 
    8402         320 :     i_tableoid = PQfnumber(res, "tableoid");
    8403         320 :     i_oid = PQfnumber(res, "oid");
    8404         320 :     i_tgrelid = PQfnumber(res, "tgrelid");
    8405         320 :     i_tgname = PQfnumber(res, "tgname");
    8406         320 :     i_tgenabled = PQfnumber(res, "tgenabled");
    8407         320 :     i_tgispartition = PQfnumber(res, "tgispartition");
    8408         320 :     i_tgdef = PQfnumber(res, "tgdef");
    8409             : 
    8410         320 :     tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
    8411             : 
    8412             :     /*
    8413             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    8414             :      * j is handled by the inner loop.
    8415             :      */
    8416         320 :     curtblindx = -1;
    8417         952 :     for (int j = 0; j < ntups;)
    8418             :     {
    8419         632 :         Oid         tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
    8420         632 :         TableInfo  *tbinfo = NULL;
    8421             :         int         numtrigs;
    8422             : 
    8423             :         /* Count rows for this table */
    8424        1066 :         for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
    8425         960 :             if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
    8426         526 :                 break;
    8427             : 
    8428             :         /*
    8429             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    8430             :          * order.
    8431             :          */
    8432       32592 :         while (++curtblindx < numTables)
    8433             :         {
    8434       32592 :             tbinfo = &tblinfo[curtblindx];
    8435       32592 :             if (tbinfo->dobj.catId.oid == tgrelid)
    8436         632 :                 break;
    8437             :         }
    8438         632 :         if (curtblindx >= numTables)
    8439           0 :             pg_fatal("unrecognized table OID %u", tgrelid);
    8440             : 
    8441             :         /* Save data for this table */
    8442         632 :         tbinfo->triggers = tginfo + j;
    8443         632 :         tbinfo->numTriggers = numtrigs;
    8444             : 
    8445        1698 :         for (int c = 0; c < numtrigs; c++, j++)
    8446             :         {
    8447        1066 :             tginfo[j].dobj.objType = DO_TRIGGER;
    8448        1066 :             tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    8449        1066 :             tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    8450        1066 :             AssignDumpId(&tginfo[j].dobj);
    8451        1066 :             tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
    8452        1066 :             tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
    8453        1066 :             tginfo[j].tgtable = tbinfo;
    8454        1066 :             tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
    8455        1066 :             tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
    8456        1066 :             tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
    8457             :         }
    8458             :     }
    8459             : 
    8460         320 :     PQclear(res);
    8461             : 
    8462         320 :     destroyPQExpBuffer(query);
    8463         320 :     destroyPQExpBuffer(tbloids);
    8464         320 : }
    8465             : 
    8466             : /*
    8467             :  * getEventTriggers
    8468             :  *    get information about event triggers
    8469             :  */
    8470             : void
    8471         320 : getEventTriggers(Archive *fout)
    8472             : {
    8473             :     int         i;
    8474             :     PQExpBuffer query;
    8475             :     PGresult   *res;
    8476             :     EventTriggerInfo *evtinfo;
    8477             :     int         i_tableoid,
    8478             :                 i_oid,
    8479             :                 i_evtname,
    8480             :                 i_evtevent,
    8481             :                 i_evtowner,
    8482             :                 i_evttags,
    8483             :                 i_evtfname,
    8484             :                 i_evtenabled;
    8485             :     int         ntups;
    8486             : 
    8487             :     /* Before 9.3, there are no event triggers */
    8488         320 :     if (fout->remoteVersion < 90300)
    8489           0 :         return;
    8490             : 
    8491         320 :     query = createPQExpBuffer();
    8492             : 
    8493         320 :     appendPQExpBufferStr(query,
    8494             :                          "SELECT e.tableoid, e.oid, evtname, evtenabled, "
    8495             :                          "evtevent, evtowner, "
    8496             :                          "array_to_string(array("
    8497             :                          "select quote_literal(x) "
    8498             :                          " from unnest(evttags) as t(x)), ', ') as evttags, "
    8499             :                          "e.evtfoid::regproc as evtfname "
    8500             :                          "FROM pg_event_trigger e "
    8501             :                          "ORDER BY e.oid");
    8502             : 
    8503         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8504             : 
    8505         320 :     ntups = PQntuples(res);
    8506             : 
    8507         320 :     evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
    8508             : 
    8509         320 :     i_tableoid = PQfnumber(res, "tableoid");
    8510         320 :     i_oid = PQfnumber(res, "oid");
    8511         320 :     i_evtname = PQfnumber(res, "evtname");
    8512         320 :     i_evtevent = PQfnumber(res, "evtevent");
    8513         320 :     i_evtowner = PQfnumber(res, "evtowner");
    8514         320 :     i_evttags = PQfnumber(res, "evttags");
    8515         320 :     i_evtfname = PQfnumber(res, "evtfname");
    8516         320 :     i_evtenabled = PQfnumber(res, "evtenabled");
    8517             : 
    8518         428 :     for (i = 0; i < ntups; i++)
    8519             :     {
    8520         108 :         evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
    8521         108 :         evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8522         108 :         evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8523         108 :         AssignDumpId(&evtinfo[i].dobj);
    8524         108 :         evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
    8525         108 :         evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
    8526         108 :         evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
    8527         108 :         evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
    8528         108 :         evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
    8529         108 :         evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
    8530         108 :         evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
    8531             : 
    8532             :         /* Decide whether we want to dump it */
    8533         108 :         selectDumpableObject(&(evtinfo[i].dobj), fout);
    8534             :     }
    8535             : 
    8536         320 :     PQclear(res);
    8537             : 
    8538         320 :     destroyPQExpBuffer(query);
    8539             : }
    8540             : 
    8541             : /*
    8542             :  * getProcLangs
    8543             :  *    get basic information about every procedural language in the system
    8544             :  *
    8545             :  * NB: this must run after getFuncs() because we assume we can do
    8546             :  * findFuncByOid().
    8547             :  */
    8548             : void
    8549         320 : getProcLangs(Archive *fout)
    8550             : {
    8551             :     PGresult   *res;
    8552             :     int         ntups;
    8553             :     int         i;
    8554         320 :     PQExpBuffer query = createPQExpBuffer();
    8555             :     ProcLangInfo *planginfo;
    8556             :     int         i_tableoid;
    8557             :     int         i_oid;
    8558             :     int         i_lanname;
    8559             :     int         i_lanpltrusted;
    8560             :     int         i_lanplcallfoid;
    8561             :     int         i_laninline;
    8562             :     int         i_lanvalidator;
    8563             :     int         i_lanacl;
    8564             :     int         i_acldefault;
    8565             :     int         i_lanowner;
    8566             : 
    8567         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8568             :                          "lanname, lanpltrusted, lanplcallfoid, "
    8569             :                          "laninline, lanvalidator, "
    8570             :                          "lanacl, "
    8571             :                          "acldefault('l', lanowner) AS acldefault, "
    8572             :                          "lanowner "
    8573             :                          "FROM pg_language "
    8574             :                          "WHERE lanispl "
    8575             :                          "ORDER BY oid");
    8576             : 
    8577         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8578             : 
    8579         320 :     ntups = PQntuples(res);
    8580             : 
    8581         320 :     planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
    8582             : 
    8583         320 :     i_tableoid = PQfnumber(res, "tableoid");
    8584         320 :     i_oid = PQfnumber(res, "oid");
    8585         320 :     i_lanname = PQfnumber(res, "lanname");
    8586         320 :     i_lanpltrusted = PQfnumber(res, "lanpltrusted");
    8587         320 :     i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
    8588         320 :     i_laninline = PQfnumber(res, "laninline");
    8589         320 :     i_lanvalidator = PQfnumber(res, "lanvalidator");
    8590         320 :     i_lanacl = PQfnumber(res, "lanacl");
    8591         320 :     i_acldefault = PQfnumber(res, "acldefault");
    8592         320 :     i_lanowner = PQfnumber(res, "lanowner");
    8593             : 
    8594         734 :     for (i = 0; i < ntups; i++)
    8595             :     {
    8596         414 :         planginfo[i].dobj.objType = DO_PROCLANG;
    8597         414 :         planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8598         414 :         planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8599         414 :         AssignDumpId(&planginfo[i].dobj);
    8600             : 
    8601         414 :         planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
    8602         414 :         planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
    8603         414 :         planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    8604         414 :         planginfo[i].dacl.privtype = 0;
    8605         414 :         planginfo[i].dacl.initprivs = NULL;
    8606         414 :         planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
    8607         414 :         planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
    8608         414 :         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
    8609         414 :         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
    8610         414 :         planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
    8611             : 
    8612             :         /* Decide whether we want to dump it */
    8613         414 :         selectDumpableProcLang(&(planginfo[i]), fout);
    8614             : 
    8615             :         /* Mark whether language has an ACL */
    8616         414 :         if (!PQgetisnull(res, i, i_lanacl))
    8617          94 :             planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    8618             :     }
    8619             : 
    8620         320 :     PQclear(res);
    8621             : 
    8622         320 :     destroyPQExpBuffer(query);
    8623         320 : }
    8624             : 
    8625             : /*
    8626             :  * getCasts
    8627             :  *    get basic information about most casts in the system
    8628             :  *
    8629             :  * Skip casts from a range to its multirange, since we'll create those
    8630             :  * automatically.
    8631             :  */
    8632             : void
    8633         320 : getCasts(Archive *fout)
    8634             : {
    8635             :     PGresult   *res;
    8636             :     int         ntups;
    8637             :     int         i;
    8638         320 :     PQExpBuffer query = createPQExpBuffer();
    8639             :     CastInfo   *castinfo;
    8640             :     int         i_tableoid;
    8641             :     int         i_oid;
    8642             :     int         i_castsource;
    8643             :     int         i_casttarget;
    8644             :     int         i_castfunc;
    8645             :     int         i_castcontext;
    8646             :     int         i_castmethod;
    8647             : 
    8648         320 :     if (fout->remoteVersion >= 140000)
    8649             :     {
    8650         320 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8651             :                              "castsource, casttarget, castfunc, castcontext, "
    8652             :                              "castmethod "
    8653             :                              "FROM pg_cast c "
    8654             :                              "WHERE NOT EXISTS ( "
    8655             :                              "SELECT 1 FROM pg_range r "
    8656             :                              "WHERE c.castsource = r.rngtypid "
    8657             :                              "AND c.casttarget = r.rngmultitypid "
    8658             :                              ") "
    8659             :                              "ORDER BY 3,4");
    8660             :     }
    8661             :     else
    8662             :     {
    8663           0 :         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8664             :                              "castsource, casttarget, castfunc, castcontext, "
    8665             :                              "castmethod "
    8666             :                              "FROM pg_cast ORDER BY 3,4");
    8667             :     }
    8668             : 
    8669         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8670             : 
    8671         320 :     ntups = PQntuples(res);
    8672             : 
    8673         320 :     castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
    8674             : 
    8675         320 :     i_tableoid = PQfnumber(res, "tableoid");
    8676         320 :     i_oid = PQfnumber(res, "oid");
    8677         320 :     i_castsource = PQfnumber(res, "castsource");
    8678         320 :     i_casttarget = PQfnumber(res, "casttarget");
    8679         320 :     i_castfunc = PQfnumber(res, "castfunc");
    8680         320 :     i_castcontext = PQfnumber(res, "castcontext");
    8681         320 :     i_castmethod = PQfnumber(res, "castmethod");
    8682             : 
    8683       71858 :     for (i = 0; i < ntups; i++)
    8684             :     {
    8685             :         PQExpBufferData namebuf;
    8686             :         TypeInfo   *sTypeInfo;
    8687             :         TypeInfo   *tTypeInfo;
    8688             : 
    8689       71538 :         castinfo[i].dobj.objType = DO_CAST;
    8690       71538 :         castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8691       71538 :         castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8692       71538 :         AssignDumpId(&castinfo[i].dobj);
    8693       71538 :         castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
    8694       71538 :         castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
    8695       71538 :         castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
    8696       71538 :         castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
    8697       71538 :         castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
    8698             : 
    8699             :         /*
    8700             :          * Try to name cast as concatenation of typnames.  This is only used
    8701             :          * for purposes of sorting.  If we fail to find either type, the name
    8702             :          * will be an empty string.
    8703             :          */
    8704       71538 :         initPQExpBuffer(&namebuf);
    8705       71538 :         sTypeInfo = findTypeByOid(castinfo[i].castsource);
    8706       71538 :         tTypeInfo = findTypeByOid(castinfo[i].casttarget);
    8707       71538 :         if (sTypeInfo && tTypeInfo)
    8708       71538 :             appendPQExpBuffer(&namebuf, "%s %s",
    8709             :                               sTypeInfo->dobj.name, tTypeInfo->dobj.name);
    8710       71538 :         castinfo[i].dobj.name = namebuf.data;
    8711             : 
    8712             :         /* Decide whether we want to dump it */
    8713       71538 :         selectDumpableCast(&(castinfo[i]), fout);
    8714             :     }
    8715             : 
    8716         320 :     PQclear(res);
    8717             : 
    8718         320 :     destroyPQExpBuffer(query);
    8719         320 : }
    8720             : 
    8721             : static char *
    8722         184 : get_language_name(Archive *fout, Oid langid)
    8723             : {
    8724             :     PQExpBuffer query;
    8725             :     PGresult   *res;
    8726             :     char       *lanname;
    8727             : 
    8728         184 :     query = createPQExpBuffer();
    8729         184 :     appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
    8730         184 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
    8731         184 :     lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
    8732         184 :     destroyPQExpBuffer(query);
    8733         184 :     PQclear(res);
    8734             : 
    8735         184 :     return lanname;
    8736             : }
    8737             : 
    8738             : /*
    8739             :  * getTransforms
    8740             :  *    get basic information about every transform in the system
    8741             :  */
    8742             : void
    8743         320 : getTransforms(Archive *fout)
    8744             : {
    8745             :     PGresult   *res;
    8746             :     int         ntups;
    8747             :     int         i;
    8748             :     PQExpBuffer query;
    8749             :     TransformInfo *transforminfo;
    8750             :     int         i_tableoid;
    8751             :     int         i_oid;
    8752             :     int         i_trftype;
    8753             :     int         i_trflang;
    8754             :     int         i_trffromsql;
    8755             :     int         i_trftosql;
    8756             : 
    8757             :     /* Transforms didn't exist pre-9.5 */
    8758         320 :     if (fout->remoteVersion < 90500)
    8759           0 :         return;
    8760             : 
    8761         320 :     query = createPQExpBuffer();
    8762             : 
    8763         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, "
    8764             :                          "trftype, trflang, trffromsql::oid, trftosql::oid "
    8765             :                          "FROM pg_transform "
    8766             :                          "ORDER BY 3,4");
    8767             : 
    8768         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    8769             : 
    8770         320 :     ntups = PQntuples(res);
    8771             : 
    8772         320 :     transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
    8773             : 
    8774         320 :     i_tableoid = PQfnumber(res, "tableoid");
    8775         320 :     i_oid = PQfnumber(res, "oid");
    8776         320 :     i_trftype = PQfnumber(res, "trftype");
    8777         320 :     i_trflang = PQfnumber(res, "trflang");
    8778         320 :     i_trffromsql = PQfnumber(res, "trffromsql");
    8779         320 :     i_trftosql = PQfnumber(res, "trftosql");
    8780             : 
    8781         428 :     for (i = 0; i < ntups; i++)
    8782             :     {
    8783             :         PQExpBufferData namebuf;
    8784             :         TypeInfo   *typeInfo;
    8785             :         char       *lanname;
    8786             : 
    8787         108 :         transforminfo[i].dobj.objType = DO_TRANSFORM;
    8788         108 :         transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    8789         108 :         transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    8790         108 :         AssignDumpId(&transforminfo[i].dobj);
    8791         108 :         transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
    8792         108 :         transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
    8793         108 :         transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
    8794         108 :         transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
    8795             : 
    8796             :         /*
    8797             :          * Try to name transform as concatenation of type and language name.
    8798             :          * This is only used for purposes of sorting.  If we fail to find
    8799             :          * either, the name will be an empty string.
    8800             :          */
    8801         108 :         initPQExpBuffer(&namebuf);
    8802         108 :         typeInfo = findTypeByOid(transforminfo[i].trftype);
    8803         108 :         lanname = get_language_name(fout, transforminfo[i].trflang);
    8804         108 :         if (typeInfo && lanname)
    8805         108 :             appendPQExpBuffer(&namebuf, "%s %s",
    8806             :                               typeInfo->dobj.name, lanname);
    8807         108 :         transforminfo[i].dobj.name = namebuf.data;
    8808         108 :         free(lanname);
    8809             : 
    8810             :         /* Decide whether we want to dump it */
    8811         108 :         selectDumpableObject(&(transforminfo[i].dobj), fout);
    8812             :     }
    8813             : 
    8814         320 :     PQclear(res);
    8815             : 
    8816         320 :     destroyPQExpBuffer(query);
    8817             : }
    8818             : 
    8819             : /*
    8820             :  * getTableAttrs -
    8821             :  *    for each interesting table, read info about its attributes
    8822             :  *    (names, types, default values, CHECK constraints, etc)
    8823             :  *
    8824             :  *  modifies tblinfo
    8825             :  */
    8826             : void
    8827         320 : getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
    8828             : {
    8829         320 :     DumpOptions *dopt = fout->dopt;
    8830         320 :     PQExpBuffer q = createPQExpBuffer();
    8831         320 :     PQExpBuffer tbloids = createPQExpBuffer();
    8832         320 :     PQExpBuffer checkoids = createPQExpBuffer();
    8833             :     PGresult   *res;
    8834             :     int         ntups;
    8835             :     int         curtblindx;
    8836             :     int         i_attrelid;
    8837             :     int         i_attnum;
    8838             :     int         i_attname;
    8839             :     int         i_atttypname;
    8840             :     int         i_attstattarget;
    8841             :     int         i_attstorage;
    8842             :     int         i_typstorage;
    8843             :     int         i_attidentity;
    8844             :     int         i_attgenerated;
    8845             :     int         i_attisdropped;
    8846             :     int         i_attlen;
    8847             :     int         i_attalign;
    8848             :     int         i_attislocal;
    8849             :     int         i_notnull_name;
    8850             :     int         i_notnull_noinherit;
    8851             :     int         i_notnull_islocal;
    8852             :     int         i_attoptions;
    8853             :     int         i_attcollation;
    8854             :     int         i_attcompression;
    8855             :     int         i_attfdwoptions;
    8856             :     int         i_attmissingval;
    8857             :     int         i_atthasdef;
    8858             : 
    8859             :     /*
    8860             :      * We want to perform just one query against pg_attribute, and then just
    8861             :      * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
    8862             :      * (for CHECK constraints and for NOT NULL constraints).  However, we
    8863             :      * mustn't try to select every row of those catalogs and then sort it out
    8864             :      * on the client side, because some of the server-side functions we need
    8865             :      * would be unsafe to apply to tables we don't have lock on.  Hence, we
    8866             :      * build an array of the OIDs of tables we care about (and now have lock
    8867             :      * on!), and use a WHERE clause to constrain which rows are selected.
    8868             :      */
    8869         320 :     appendPQExpBufferChar(tbloids, '{');
    8870         320 :     appendPQExpBufferChar(checkoids, '{');
    8871       85060 :     for (int i = 0; i < numTables; i++)
    8872             :     {
    8873       84740 :         TableInfo  *tbinfo = &tblinfo[i];
    8874             : 
    8875             :         /* Don't bother to collect info for sequences */
    8876       84740 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
    8877        1278 :             continue;
    8878             : 
    8879             :         /* Don't bother with uninteresting tables, either */
    8880       83462 :         if (!tbinfo->interesting)
    8881       70952 :             continue;
    8882             : 
    8883             :         /* OK, we need info for this table */
    8884       12510 :         if (tbloids->len > 1) /* do we have more than the '{'? */
    8885       12298 :             appendPQExpBufferChar(tbloids, ',');
    8886       12510 :         appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    8887             : 
    8888       12510 :         if (tbinfo->ncheck > 0)
    8889             :         {
    8890             :             /* Also make a list of the ones with check constraints */
    8891        1088 :             if (checkoids->len > 1) /* do we have more than the '{'? */
    8892         946 :                 appendPQExpBufferChar(checkoids, ',');
    8893        1088 :             appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
    8894             :         }
    8895             :     }
    8896         320 :     appendPQExpBufferChar(tbloids, '}');
    8897         320 :     appendPQExpBufferChar(checkoids, '}');
    8898             : 
    8899             :     /*
    8900             :      * Find all the user attributes and their types.
    8901             :      *
    8902             :      * Since we only want to dump COLLATE clauses for attributes whose
    8903             :      * collation is different from their type's default, we use a CASE here to
    8904             :      * suppress uninteresting attcollations cheaply.
    8905             :      */
    8906         320 :     appendPQExpBufferStr(q,
    8907             :                          "SELECT\n"
    8908             :                          "a.attrelid,\n"
    8909             :                          "a.attnum,\n"
    8910             :                          "a.attname,\n"
    8911             :                          "a.attstattarget,\n"
    8912             :                          "a.attstorage,\n"
    8913             :                          "t.typstorage,\n"
    8914             :                          "a.atthasdef,\n"
    8915             :                          "a.attisdropped,\n"
    8916             :                          "a.attlen,\n"
    8917             :                          "a.attalign,\n"
    8918             :                          "a.attislocal,\n"
    8919             :                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
    8920             :                          "array_to_string(a.attoptions, ', ') AS attoptions,\n"
    8921             :                          "CASE WHEN a.attcollation <> t.typcollation "
    8922             :                          "THEN a.attcollation ELSE 0 END AS attcollation,\n"
    8923             :                          "pg_catalog.array_to_string(ARRAY("
    8924             :                          "SELECT pg_catalog.quote_ident(option_name) || "
    8925             :                          "' ' || pg_catalog.quote_literal(option_value) "
    8926             :                          "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
    8927             :                          "ORDER BY option_name"
    8928             :                          "), E',\n    ') AS attfdwoptions,\n");
    8929             : 
    8930             :     /*
    8931             :      * Find out any NOT NULL markings for each column.  In 18 and up we read
    8932             :      * pg_constraint to obtain the constraint name.  notnull_noinherit is set
    8933             :      * according to the NO INHERIT property.  For versions prior to 18, we
    8934             :      * store an empty string as the name when a constraint is marked as
    8935             :      * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
    8936             :      * without a name); also, such cases are never NO INHERIT.
    8937             :      *
    8938             :      * We track in notnull_islocal whether the constraint was defined directly
    8939             :      * in this table or via an ancestor, for binary upgrade.  flagInhAttrs
    8940             :      * might modify this later for servers older than 18; it's also in charge
    8941             :      * of determining the correct inhcount.
    8942             :      */
    8943         320 :     if (fout->remoteVersion >= 180000)
    8944         320 :         appendPQExpBufferStr(q,
    8945             :                              "co.conname AS notnull_name,\n"
    8946             :                              "co.connoinherit AS notnull_noinherit,\n"
    8947             :                              "co.conislocal AS notnull_islocal,\n");
    8948             :     else
    8949           0 :         appendPQExpBufferStr(q,
    8950             :                              "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
    8951             :                              "false AS notnull_noinherit,\n"
    8952             :                              "a.attislocal AS notnull_islocal,\n");
    8953             : 
    8954         320 :     if (fout->remoteVersion >= 140000)
    8955         320 :         appendPQExpBufferStr(q,
    8956             :                              "a.attcompression AS attcompression,\n");
    8957             :     else
    8958           0 :         appendPQExpBufferStr(q,
    8959             :                              "'' AS attcompression,\n");
    8960             : 
    8961         320 :     if (fout->remoteVersion >= 100000)
    8962         320 :         appendPQExpBufferStr(q,
    8963             :                              "a.attidentity,\n");
    8964             :     else
    8965           0 :         appendPQExpBufferStr(q,
    8966             :                              "'' AS attidentity,\n");
    8967             : 
    8968         320 :     if (fout->remoteVersion >= 110000)
    8969         320 :         appendPQExpBufferStr(q,
    8970             :                              "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
    8971             :                              "THEN a.attmissingval ELSE null END AS attmissingval,\n");
    8972             :     else
    8973           0 :         appendPQExpBufferStr(q,
    8974             :                              "NULL AS attmissingval,\n");
    8975             : 
    8976         320 :     if (fout->remoteVersion >= 120000)
    8977         320 :         appendPQExpBufferStr(q,
    8978             :                              "a.attgenerated\n");
    8979             :     else
    8980           0 :         appendPQExpBufferStr(q,
    8981             :                              "'' AS attgenerated\n");
    8982             : 
    8983             :     /* need left join to pg_type to not fail on dropped columns ... */
    8984         320 :     appendPQExpBuffer(q,
    8985             :                       "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    8986             :                       "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
    8987             :                       "LEFT JOIN pg_catalog.pg_type t "
    8988             :                       "ON (a.atttypid = t.oid)\n",
    8989             :                       tbloids->data);
    8990             : 
    8991             :     /*
    8992             :      * In versions 18 and up, we need pg_constraint for explicit NOT NULL
    8993             :      * entries.  Also, we need to know if the NOT NULL for each column is
    8994             :      * backing a primary key.
    8995             :      */
    8996         320 :     if (fout->remoteVersion >= 180000)
    8997         320 :         appendPQExpBufferStr(q,
    8998             :                              " LEFT JOIN pg_catalog.pg_constraint co ON "
    8999             :                              "(a.attrelid = co.conrelid\n"
    9000             :                              "   AND co.contype = 'n' AND "
    9001             :                              "co.conkey = array[a.attnum])\n");
    9002             : 
    9003         320 :     appendPQExpBufferStr(q,
    9004             :                          "WHERE a.attnum > 0::pg_catalog.int2\n"
    9005             :                          "ORDER BY a.attrelid, a.attnum");
    9006             : 
    9007         320 :     res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9008             : 
    9009         320 :     ntups = PQntuples(res);
    9010             : 
    9011         320 :     i_attrelid = PQfnumber(res, "attrelid");
    9012         320 :     i_attnum = PQfnumber(res, "attnum");
    9013         320 :     i_attname = PQfnumber(res, "attname");
    9014         320 :     i_atttypname = PQfnumber(res, "atttypname");
    9015         320 :     i_attstattarget = PQfnumber(res, "attstattarget");
    9016         320 :     i_attstorage = PQfnumber(res, "attstorage");
    9017         320 :     i_typstorage = PQfnumber(res, "typstorage");
    9018         320 :     i_attidentity = PQfnumber(res, "attidentity");
    9019         320 :     i_attgenerated = PQfnumber(res, "attgenerated");
    9020         320 :     i_attisdropped = PQfnumber(res, "attisdropped");
    9021         320 :     i_attlen = PQfnumber(res, "attlen");
    9022         320 :     i_attalign = PQfnumber(res, "attalign");
    9023         320 :     i_attislocal = PQfnumber(res, "attislocal");
    9024         320 :     i_notnull_name = PQfnumber(res, "notnull_name");
    9025         320 :     i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
    9026         320 :     i_notnull_islocal = PQfnumber(res, "notnull_islocal");
    9027         320 :     i_attoptions = PQfnumber(res, "attoptions");
    9028         320 :     i_attcollation = PQfnumber(res, "attcollation");
    9029         320 :     i_attcompression = PQfnumber(res, "attcompression");
    9030         320 :     i_attfdwoptions = PQfnumber(res, "attfdwoptions");
    9031         320 :     i_attmissingval = PQfnumber(res, "attmissingval");
    9032         320 :     i_atthasdef = PQfnumber(res, "atthasdef");
    9033             : 
    9034             :     /* Within the next loop, we'll accumulate OIDs of tables with defaults */
    9035         320 :     resetPQExpBuffer(tbloids);
    9036         320 :     appendPQExpBufferChar(tbloids, '{');
    9037             : 
    9038             :     /*
    9039             :      * Outer loop iterates once per table, not once per row.  Incrementing of
    9040             :      * r is handled by the inner loop.
    9041             :      */
    9042         320 :     curtblindx = -1;
    9043       12542 :     for (int r = 0; r < ntups;)
    9044             :     {
    9045       12222 :         Oid         attrelid = atooid(PQgetvalue(res, r, i_attrelid));
    9046       12222 :         TableInfo  *tbinfo = NULL;
    9047             :         int         numatts;
    9048             :         bool        hasdefaults;
    9049             : 
    9050             :         /* Count rows for this table */
    9051       47592 :         for (numatts = 1; numatts < ntups - r; numatts++)
    9052       47386 :             if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
    9053       12016 :                 break;
    9054             : 
    9055             :         /*
    9056             :          * Locate the associated TableInfo; we rely on tblinfo[] being in OID
    9057             :          * order.
    9058             :          */
    9059       56508 :         while (++curtblindx < numTables)
    9060             :         {
    9061       56508 :             tbinfo = &tblinfo[curtblindx];
    9062       56508 :             if (tbinfo->dobj.catId.oid == attrelid)
    9063       12222 :                 break;
    9064             :         }
    9065       12222 :         if (curtblindx >= numTables)
    9066           0 :             pg_fatal("unrecognized table OID %u", attrelid);
    9067             :         /* cross-check that we only got requested tables */
    9068       12222 :         if (tbinfo->relkind == RELKIND_SEQUENCE ||
    9069       12222 :             !tbinfo->interesting)
    9070           0 :             pg_fatal("unexpected column data for table \"%s\"",
    9071             :                      tbinfo->dobj.name);
    9072             : 
    9073             :         /* Save data for this table */
    9074       12222 :         tbinfo->numatts = numatts;
    9075       12222 :         tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
    9076       12222 :         tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
    9077       12222 :         tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
    9078       12222 :         tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
    9079       12222 :         tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
    9080       12222 :         tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
    9081       12222 :         tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
    9082       12222 :         tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
    9083       12222 :         tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
    9084       12222 :         tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
    9085       12222 :         tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9086       12222 :         tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9087       12222 :         tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
    9088       12222 :         tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
    9089       12222 :         tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
    9090       12222 :         tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
    9091       12222 :         tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
    9092       12222 :         tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
    9093       12222 :         tbinfo->notnull_islocal = (bool *) pg_malloc(numatts * sizeof(bool));
    9094       12222 :         tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
    9095       12222 :         hasdefaults = false;
    9096             : 
    9097       59814 :         for (int j = 0; j < numatts; j++, r++)
    9098             :         {
    9099       47592 :             if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
    9100           0 :                 pg_fatal("invalid column numbering in table \"%s\"",
    9101             :                          tbinfo->dobj.name);
    9102       47592 :             tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
    9103       47592 :             tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
    9104       47592 :             if (PQgetisnull(res, r, i_attstattarget))
    9105       47508 :                 tbinfo->attstattarget[j] = -1;
    9106             :             else
    9107          84 :                 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
    9108       47592 :             tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
    9109       47592 :             tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
    9110       47592 :             tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
    9111       47592 :             tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
    9112       47592 :             tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
    9113       47592 :             tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
    9114       47592 :             tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
    9115       47592 :             tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
    9116       47592 :             tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
    9117             : 
    9118             :             /* Handle not-null constraint name and flags */
    9119       47592 :             determineNotNullFlags(fout, res, r,
    9120             :                                   tbinfo, j,
    9121             :                                   i_notnull_name, i_notnull_noinherit,
    9122             :                                   i_notnull_islocal);
    9123             : 
    9124       47592 :             tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
    9125       47592 :             tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
    9126       47592 :             tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
    9127       47592 :             tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
    9128       47592 :             tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
    9129       47592 :             tbinfo->attrdefs[j] = NULL; /* fix below */
    9130       47592 :             if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
    9131        2490 :                 hasdefaults = true;
    9132             :         }
    9133             : 
    9134       12222 :         if (hasdefaults)
    9135             :         {
    9136             :             /* Collect OIDs of interesting tables that have defaults */
    9137        1888 :             if (tbloids->len > 1) /* do we have more than the '{'? */
    9138        1748 :                 appendPQExpBufferChar(tbloids, ',');
    9139        1888 :             appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
    9140             :         }
    9141             :     }
    9142             : 
    9143         320 :     PQclear(res);
    9144             : 
    9145             :     /*
    9146             :      * Now get info about column defaults.  This is skipped for a data-only
    9147             :      * dump, as it is only needed for table schemas.
    9148             :      */
    9149         320 :     if (dopt->dumpSchema && tbloids->len > 1)
    9150             :     {
    9151             :         AttrDefInfo *attrdefs;
    9152             :         int         numDefaults;
    9153         124 :         TableInfo  *tbinfo = NULL;
    9154             : 
    9155         124 :         pg_log_info("finding table default expressions");
    9156             : 
    9157         124 :         appendPQExpBufferChar(tbloids, '}');
    9158             : 
    9159         124 :         printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
    9160             :                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
    9161             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9162             :                           "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
    9163             :                           "ORDER BY a.adrelid, a.adnum",
    9164             :                           tbloids->data);
    9165             : 
    9166         124 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9167             : 
    9168         124 :         numDefaults = PQntuples(res);
    9169         124 :         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
    9170             : 
    9171         124 :         curtblindx = -1;
    9172        2418 :         for (int j = 0; j < numDefaults; j++)
    9173             :         {
    9174        2294 :             Oid         adtableoid = atooid(PQgetvalue(res, j, 0));
    9175        2294 :             Oid         adoid = atooid(PQgetvalue(res, j, 1));
    9176        2294 :             Oid         adrelid = atooid(PQgetvalue(res, j, 2));
    9177        2294 :             int         adnum = atoi(PQgetvalue(res, j, 3));
    9178        2294 :             char       *adsrc = PQgetvalue(res, j, 4);
    9179             : 
    9180             :             /*
    9181             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9182             :              * OID order.
    9183             :              */
    9184        2294 :             if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
    9185             :             {
    9186       37794 :                 while (++curtblindx < numTables)
    9187             :                 {
    9188       37794 :                     tbinfo = &tblinfo[curtblindx];
    9189       37794 :                     if (tbinfo->dobj.catId.oid == adrelid)
    9190        1752 :                         break;
    9191             :                 }
    9192        1752 :                 if (curtblindx >= numTables)
    9193           0 :                     pg_fatal("unrecognized table OID %u", adrelid);
    9194             :             }
    9195             : 
    9196        2294 :             if (adnum <= 0 || adnum > tbinfo->numatts)
    9197           0 :                 pg_fatal("invalid adnum value %d for table \"%s\"",
    9198             :                          adnum, tbinfo->dobj.name);
    9199             : 
    9200             :             /*
    9201             :              * dropped columns shouldn't have defaults, but just in case,
    9202             :              * ignore 'em
    9203             :              */
    9204        2294 :             if (tbinfo->attisdropped[adnum - 1])
    9205           0 :                 continue;
    9206             : 
    9207        2294 :             attrdefs[j].dobj.objType = DO_ATTRDEF;
    9208        2294 :             attrdefs[j].dobj.catId.tableoid = adtableoid;
    9209        2294 :             attrdefs[j].dobj.catId.oid = adoid;
    9210        2294 :             AssignDumpId(&attrdefs[j].dobj);
    9211        2294 :             attrdefs[j].adtable = tbinfo;
    9212        2294 :             attrdefs[j].adnum = adnum;
    9213        2294 :             attrdefs[j].adef_expr = pg_strdup(adsrc);
    9214             : 
    9215        2294 :             attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
    9216        2294 :             attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
    9217             : 
    9218        2294 :             attrdefs[j].dobj.dump = tbinfo->dobj.dump;
    9219             : 
    9220             :             /*
    9221             :              * Figure out whether the default/generation expression should be
    9222             :              * dumped as part of the main CREATE TABLE (or similar) command or
    9223             :              * as a separate ALTER TABLE (or similar) command. The preference
    9224             :              * is to put it into the CREATE command, but in some cases that's
    9225             :              * not possible.
    9226             :              */
    9227        2294 :             if (tbinfo->attgenerated[adnum - 1])
    9228             :             {
    9229             :                 /*
    9230             :                  * Column generation expressions cannot be dumped separately,
    9231             :                  * because there is no syntax for it.  By setting separate to
    9232             :                  * false here we prevent the "default" from being processed as
    9233             :                  * its own dumpable object.  Later, flagInhAttrs() will mark
    9234             :                  * it as not to be dumped at all, if possible (that is, if it
    9235             :                  * can be inherited from a parent).
    9236             :                  */
    9237        1254 :                 attrdefs[j].separate = false;
    9238             :             }
    9239        1040 :             else if (tbinfo->relkind == RELKIND_VIEW)
    9240             :             {
    9241             :                 /*
    9242             :                  * Defaults on a VIEW must always be dumped as separate ALTER
    9243             :                  * TABLE commands.
    9244             :                  */
    9245          68 :                 attrdefs[j].separate = true;
    9246             :             }
    9247         972 :             else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
    9248             :             {
    9249             :                 /* column will be suppressed, print default separately */
    9250           8 :                 attrdefs[j].separate = true;
    9251             :             }
    9252             :             else
    9253             :             {
    9254         964 :                 attrdefs[j].separate = false;
    9255             :             }
    9256             : 
    9257        2294 :             if (!attrdefs[j].separate)
    9258             :             {
    9259             :                 /*
    9260             :                  * Mark the default as needing to appear before the table, so
    9261             :                  * that any dependencies it has must be emitted before the
    9262             :                  * CREATE TABLE.  If this is not possible, we'll change to
    9263             :                  * "separate" mode while sorting dependencies.
    9264             :                  */
    9265        2218 :                 addObjectDependency(&tbinfo->dobj,
    9266        2218 :                                     attrdefs[j].dobj.dumpId);
    9267             :             }
    9268             : 
    9269        2294 :             tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
    9270             :         }
    9271             : 
    9272         124 :         PQclear(res);
    9273             :     }
    9274             : 
    9275             :     /*
    9276             :      * Get info about table CHECK constraints.  This is skipped for a
    9277             :      * data-only dump, as it is only needed for table schemas.
    9278             :      */
    9279         320 :     if (dopt->dumpSchema && checkoids->len > 2)
    9280             :     {
    9281             :         ConstraintInfo *constrs;
    9282             :         int         numConstrs;
    9283             :         int         i_tableoid;
    9284             :         int         i_oid;
    9285             :         int         i_conrelid;
    9286             :         int         i_conname;
    9287             :         int         i_consrc;
    9288             :         int         i_conislocal;
    9289             :         int         i_convalidated;
    9290             : 
    9291         126 :         pg_log_info("finding table check constraints");
    9292             : 
    9293         126 :         resetPQExpBuffer(q);
    9294         126 :         appendPQExpBuffer(q,
    9295             :                           "SELECT c.tableoid, c.oid, conrelid, conname, "
    9296             :                           "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
    9297             :                           "conislocal, convalidated "
    9298             :                           "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
    9299             :                           "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
    9300             :                           "WHERE contype = 'c' "
    9301             :                           "ORDER BY c.conrelid, c.conname",
    9302             :                           checkoids->data);
    9303             : 
    9304         126 :         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
    9305             : 
    9306         126 :         numConstrs = PQntuples(res);
    9307         126 :         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
    9308             : 
    9309         126 :         i_tableoid = PQfnumber(res, "tableoid");
    9310         126 :         i_oid = PQfnumber(res, "oid");
    9311         126 :         i_conrelid = PQfnumber(res, "conrelid");
    9312         126 :         i_conname = PQfnumber(res, "conname");
    9313         126 :         i_consrc = PQfnumber(res, "consrc");
    9314         126 :         i_conislocal = PQfnumber(res, "conislocal");
    9315         126 :         i_convalidated = PQfnumber(res, "convalidated");
    9316             : 
    9317             :         /* As above, this loop iterates once per table, not once per row */
    9318         126 :         curtblindx = -1;
    9319        1112 :         for (int j = 0; j < numConstrs;)
    9320             :         {
    9321         986 :             Oid         conrelid = atooid(PQgetvalue(res, j, i_conrelid));
    9322         986 :             TableInfo  *tbinfo = NULL;
    9323             :             int         numcons;
    9324             : 
    9325             :             /* Count rows for this table */
    9326        1264 :             for (numcons = 1; numcons < numConstrs - j; numcons++)
    9327        1138 :                 if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
    9328         860 :                     break;
    9329             : 
    9330             :             /*
    9331             :              * Locate the associated TableInfo; we rely on tblinfo[] being in
    9332             :              * OID order.
    9333             :              */
    9334       36490 :             while (++curtblindx < numTables)
    9335             :             {
    9336       36490 :                 tbinfo = &tblinfo[curtblindx];
    9337       36490 :                 if (tbinfo->dobj.catId.oid == conrelid)
    9338         986 :                     break;
    9339             :             }
    9340         986 :             if (curtblindx >= numTables)
    9341           0 :                 pg_fatal("unrecognized table OID %u", conrelid);
    9342             : 
    9343         986 :             if (numcons != tbinfo->ncheck)
    9344             :             {
    9345           0 :                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
    9346             :                                       "expected %d check constraints on table \"%s\" but found %d",
    9347             :                                       tbinfo->ncheck),
    9348             :                              tbinfo->ncheck, tbinfo->dobj.name, numcons);
    9349           0 :                 pg_log_error_hint("The system catalogs might be corrupted.");
    9350           0 :                 exit_nicely(1);
    9351             :             }
    9352             : 
    9353         986 :             tbinfo->checkexprs = constrs + j;
    9354             : 
    9355        2250 :             for (int c = 0; c < numcons; c++, j++)
    9356             :             {
    9357        1264 :                 bool        validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
    9358             : 
    9359        1264 :                 constrs[j].dobj.objType = DO_CONSTRAINT;
    9360        1264 :                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
    9361        1264 :                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
    9362        1264 :                 AssignDumpId(&constrs[j].dobj);
    9363        1264 :                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
    9364        1264 :                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
    9365        1264 :                 constrs[j].contable = tbinfo;
    9366        1264 :                 constrs[j].condomain = NULL;
    9367        1264 :                 constrs[j].contype = 'c';
    9368        1264 :                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
    9369        1264 :                 constrs[j].confrelid = InvalidOid;
    9370        1264 :                 constrs[j].conindex = 0;
    9371        1264 :                 constrs[j].condeferrable = false;
    9372        1264 :                 constrs[j].condeferred = false;
    9373        1264 :                 constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
    9374             : 
    9375             :                 /*
    9376             :                  * An unvalidated constraint needs to be dumped separately, so
    9377             :                  * that potentially-violating existing data is loaded before
    9378             :                  * the constraint.
    9379             :                  */
    9380        1264 :                 constrs[j].separate = !validated;
    9381             : 
    9382        1264 :                 constrs[j].dobj.dump = tbinfo->dobj.dump;
    9383             : 
    9384             :                 /*
    9385             :                  * Mark the constraint as needing to appear before the table
    9386             :                  * --- this is so that any other dependencies of the
    9387             :                  * constraint will be emitted before we try to create the
    9388             :                  * table.  If the constraint is to be dumped separately, it
    9389             :                  * will be dumped after data is loaded anyway, so don't do it.
    9390             :                  * (There's an automatic dependency in the opposite direction
    9391             :                  * anyway, so don't need to add one manually here.)
    9392             :                  */
    9393        1264 :                 if (!constrs[j].separate)
    9394        1134 :                     addObjectDependency(&tbinfo->dobj,
    9395        1134 :                                         constrs[j].dobj.dumpId);
    9396             : 
    9397             :                 /*
    9398             :                  * We will detect later whether the constraint must be split
    9399             :                  * out from the table definition.
    9400             :                  */
    9401             :             }
    9402             :         }
    9403             : 
    9404         126 :         PQclear(res);
    9405             :     }
    9406             : 
    9407         320 :     destroyPQExpBuffer(q);
    9408         320 :     destroyPQExpBuffer(tbloids);
    9409         320 :     destroyPQExpBuffer(checkoids);
    9410         320 : }
    9411             : 
    9412             : /*
    9413             :  * Based on the getTableAttrs query's row corresponding to one column, set
    9414             :  * the name and flags to handle a not-null constraint for that column in
    9415             :  * the tbinfo struct.
    9416             :  *
    9417             :  * Result row 'r' is for tbinfo's attribute 'j'.
    9418             :  *
    9419             :  * There are three possibilities:
    9420             :  * 1) the column has no not-null constraints. In that case, ->notnull_constrs
    9421             :  *    (the constraint name) remains NULL.
    9422             :  * 2) The column has a constraint with no name (this is the case when
    9423             :  *    constraints come from pre-18 servers).  In this case, ->notnull_constrs
    9424             :  *    is set to the empty string; dumpTableSchema will print just "NOT NULL".
    9425             :  * 3) The column has a constraint with a known name; in that case
    9426             :  *    notnull_constrs carries that name and dumpTableSchema will print
    9427             :  *    "CONSTRAINT the_name NOT NULL".  However, if the name is the default
    9428             :  *    (table_column_not_null), there's no need to print that name in the dump,
    9429             :  *    so notnull_constrs is set to the empty string and it behaves as the case
    9430             :  *    above.
    9431             :  *
    9432             :  * In a child table that inherits from a parent already containing NOT NULL
    9433             :  * constraints and the columns in the child don't have their own NOT NULL
    9434             :  * declarations, we suppress printing constraints in the child: the
    9435             :  * constraints are acquired at the point where the child is attached to the
    9436             :  * parent.  This is tracked in ->notnull_islocal (which is set in flagInhAttrs
    9437             :  * for servers pre-18).
    9438             :  *
    9439             :  * Any of these constraints might have the NO INHERIT bit.  If so we set
    9440             :  * ->notnull_noinh and NO INHERIT will be printed by dumpTableSchema.
    9441             :  *
    9442             :  * In case 3 above, the name comparison is a bit of a hack; it actually fails
    9443             :  * to do the right thing in all but the trivial case.  However, the downside
    9444             :  * of getting it wrong is simply that the name is printed rather than
    9445             :  * suppressed, so it's not a big deal.
    9446             :  */
    9447             : static void
    9448       47592 : determineNotNullFlags(Archive *fout, PGresult *res, int r,
    9449             :                       TableInfo *tbinfo, int j,
    9450             :                       int i_notnull_name, int i_notnull_noinherit,
    9451             :                       int i_notnull_islocal)
    9452             : {
    9453       47592 :     DumpOptions *dopt = fout->dopt;
    9454             : 
    9455             :     /*
    9456             :      * notnull_noinh is straight from the query result. notnull_islocal also,
    9457             :      * though flagInhAttrs may change that one later in versions < 18.
    9458             :      */
    9459       47592 :     tbinfo->notnull_noinh[j] = PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
    9460       47592 :     tbinfo->notnull_islocal[j] = PQgetvalue(res, r, i_notnull_islocal)[0] == 't';
    9461             : 
    9462             :     /*
    9463             :      * Determine a constraint name to use.  If the column is not marked not-
    9464             :      * null, we set NULL which cues ... to do nothing.  An empty string says
    9465             :      * to print an unnamed NOT NULL, and anything else is a constraint name to
    9466             :      * use.
    9467             :      */
    9468       47592 :     if (fout->remoteVersion < 180000)
    9469             :     {
    9470             :         /*
    9471             :          * < 18 doesn't have not-null names, so an unnamed constraint is
    9472             :          * sufficient.
    9473             :          */
    9474           0 :         if (PQgetisnull(res, r, i_notnull_name))
    9475           0 :             tbinfo->notnull_constrs[j] = NULL;
    9476             :         else
    9477           0 :             tbinfo->notnull_constrs[j] = "";
    9478             :     }
    9479             :     else
    9480             :     {
    9481       47592 :         if (PQgetisnull(res, r, i_notnull_name))
    9482       42850 :             tbinfo->notnull_constrs[j] = NULL;
    9483             :         else
    9484             :         {
    9485             :             /*
    9486             :              * In binary upgrade of inheritance child tables, must have a
    9487             :              * constraint name that we can UPDATE later.
    9488             :              */
    9489        4742 :             if (dopt->binary_upgrade &&
    9490         538 :                 !tbinfo->ispartition &&
    9491         396 :                 !tbinfo->notnull_islocal)
    9492             :             {
    9493           0 :                 tbinfo->notnull_constrs[j] =
    9494           0 :                     pstrdup(PQgetvalue(res, r, i_notnull_name));
    9495             :             }
    9496             :             else
    9497             :             {
    9498             :                 char       *default_name;
    9499             : 
    9500             :                 /* XXX should match ChooseConstraintName better */
    9501        4742 :                 default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
    9502        4742 :                                         tbinfo->attnames[j]);
    9503        4742 :                 if (strcmp(default_name,
    9504        4742 :                            PQgetvalue(res, r, i_notnull_name)) == 0)
    9505        3226 :                     tbinfo->notnull_constrs[j] = "";
    9506             :                 else
    9507             :                 {
    9508        1516 :                     tbinfo->notnull_constrs[j] =
    9509        1516 :                         pstrdup(PQgetvalue(res, r, i_notnull_name));
    9510             :                 }
    9511        4742 :                 free(default_name);
    9512             :             }
    9513             :         }
    9514             :     }
    9515       47592 : }
    9516             : 
    9517             : /*
    9518             :  * Test whether a column should be printed as part of table's CREATE TABLE.
    9519             :  * Column number is zero-based.
    9520             :  *
    9521             :  * Normally this is always true, but it's false for dropped columns, as well
    9522             :  * as those that were inherited without any local definition.  (If we print
    9523             :  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
    9524             :  * For partitions, it's always true, because we want the partitions to be
    9525             :  * created independently and ATTACH PARTITION used afterwards.
    9526             :  *
    9527             :  * In binary_upgrade mode, we must print all columns and fix the attislocal/
    9528             :  * attisdropped state later, so as to keep control of the physical column
    9529             :  * order.
    9530             :  *
    9531             :  * This function exists because there are scattered nonobvious places that
    9532             :  * must be kept in sync with this decision.
    9533             :  */
    9534             : bool
    9535       78540 : shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
    9536             : {
    9537       78540 :     if (dopt->binary_upgrade)
    9538       12080 :         return true;
    9539       66460 :     if (tbinfo->attisdropped[colno])
    9540        1460 :         return false;
    9541       65000 :     return (tbinfo->attislocal[colno] || tbinfo->ispartition);
    9542             : }
    9543             : 
    9544             : 
    9545             : /*
    9546             :  * getTSParsers:
    9547             :  *    get information about all text search parsers in the system catalogs
    9548             :  */
    9549             : void
    9550         320 : getTSParsers(Archive *fout)
    9551             : {
    9552             :     PGresult   *res;
    9553             :     int         ntups;
    9554             :     int         i;
    9555             :     PQExpBuffer query;
    9556             :     TSParserInfo *prsinfo;
    9557             :     int         i_tableoid;
    9558             :     int         i_oid;
    9559             :     int         i_prsname;
    9560             :     int         i_prsnamespace;
    9561             :     int         i_prsstart;
    9562             :     int         i_prstoken;
    9563             :     int         i_prsend;
    9564             :     int         i_prsheadline;
    9565             :     int         i_prslextype;
    9566             : 
    9567         320 :     query = createPQExpBuffer();
    9568             : 
    9569             :     /*
    9570             :      * find all text search objects, including builtin ones; we filter out
    9571             :      * system-defined objects at dump-out time.
    9572             :      */
    9573             : 
    9574         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
    9575             :                          "prsstart::oid, prstoken::oid, "
    9576             :                          "prsend::oid, prsheadline::oid, prslextype::oid "
    9577             :                          "FROM pg_ts_parser");
    9578             : 
    9579         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9580             : 
    9581         320 :     ntups = PQntuples(res);
    9582             : 
    9583         320 :     prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
    9584             : 
    9585         320 :     i_tableoid = PQfnumber(res, "tableoid");
    9586         320 :     i_oid = PQfnumber(res, "oid");
    9587         320 :     i_prsname = PQfnumber(res, "prsname");
    9588         320 :     i_prsnamespace = PQfnumber(res, "prsnamespace");
    9589         320 :     i_prsstart = PQfnumber(res, "prsstart");
    9590         320 :     i_prstoken = PQfnumber(res, "prstoken");
    9591         320 :     i_prsend = PQfnumber(res, "prsend");
    9592         320 :     i_prsheadline = PQfnumber(res, "prsheadline");
    9593         320 :     i_prslextype = PQfnumber(res, "prslextype");
    9594             : 
    9595         734 :     for (i = 0; i < ntups; i++)
    9596             :     {
    9597         414 :         prsinfo[i].dobj.objType = DO_TSPARSER;
    9598         414 :         prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9599         414 :         prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9600         414 :         AssignDumpId(&prsinfo[i].dobj);
    9601         414 :         prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
    9602         828 :         prsinfo[i].dobj.namespace =
    9603         414 :             findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
    9604         414 :         prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
    9605         414 :         prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
    9606         414 :         prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
    9607         414 :         prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
    9608         414 :         prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
    9609             : 
    9610             :         /* Decide whether we want to dump it */
    9611         414 :         selectDumpableObject(&(prsinfo[i].dobj), fout);
    9612             :     }
    9613             : 
    9614         320 :     PQclear(res);
    9615             : 
    9616         320 :     destroyPQExpBuffer(query);
    9617         320 : }
    9618             : 
    9619             : /*
    9620             :  * getTSDictionaries:
    9621             :  *    get information about all text search dictionaries in the system catalogs
    9622             :  */
    9623             : void
    9624         320 : getTSDictionaries(Archive *fout)
    9625             : {
    9626             :     PGresult   *res;
    9627             :     int         ntups;
    9628             :     int         i;
    9629             :     PQExpBuffer query;
    9630             :     TSDictInfo *dictinfo;
    9631             :     int         i_tableoid;
    9632             :     int         i_oid;
    9633             :     int         i_dictname;
    9634             :     int         i_dictnamespace;
    9635             :     int         i_dictowner;
    9636             :     int         i_dicttemplate;
    9637             :     int         i_dictinitoption;
    9638             : 
    9639         320 :     query = createPQExpBuffer();
    9640             : 
    9641         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
    9642             :                          "dictnamespace, dictowner, "
    9643             :                          "dicttemplate, dictinitoption "
    9644             :                          "FROM pg_ts_dict");
    9645             : 
    9646         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9647             : 
    9648         320 :     ntups = PQntuples(res);
    9649             : 
    9650         320 :     dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
    9651             : 
    9652         320 :     i_tableoid = PQfnumber(res, "tableoid");
    9653         320 :     i_oid = PQfnumber(res, "oid");
    9654         320 :     i_dictname = PQfnumber(res, "dictname");
    9655         320 :     i_dictnamespace = PQfnumber(res, "dictnamespace");
    9656         320 :     i_dictowner = PQfnumber(res, "dictowner");
    9657         320 :     i_dictinitoption = PQfnumber(res, "dictinitoption");
    9658         320 :     i_dicttemplate = PQfnumber(res, "dicttemplate");
    9659             : 
    9660       10140 :     for (i = 0; i < ntups; i++)
    9661             :     {
    9662        9820 :         dictinfo[i].dobj.objType = DO_TSDICT;
    9663        9820 :         dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9664        9820 :         dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9665        9820 :         AssignDumpId(&dictinfo[i].dobj);
    9666        9820 :         dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
    9667       19640 :         dictinfo[i].dobj.namespace =
    9668        9820 :             findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
    9669        9820 :         dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
    9670        9820 :         dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
    9671        9820 :         if (PQgetisnull(res, i, i_dictinitoption))
    9672         414 :             dictinfo[i].dictinitoption = NULL;
    9673             :         else
    9674        9406 :             dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
    9675             : 
    9676             :         /* Decide whether we want to dump it */
    9677        9820 :         selectDumpableObject(&(dictinfo[i].dobj), fout);
    9678             :     }
    9679             : 
    9680         320 :     PQclear(res);
    9681             : 
    9682         320 :     destroyPQExpBuffer(query);
    9683         320 : }
    9684             : 
    9685             : /*
    9686             :  * getTSTemplates:
    9687             :  *    get information about all text search templates in the system catalogs
    9688             :  */
    9689             : void
    9690         320 : getTSTemplates(Archive *fout)
    9691             : {
    9692             :     PGresult   *res;
    9693             :     int         ntups;
    9694             :     int         i;
    9695             :     PQExpBuffer query;
    9696             :     TSTemplateInfo *tmplinfo;
    9697             :     int         i_tableoid;
    9698             :     int         i_oid;
    9699             :     int         i_tmplname;
    9700             :     int         i_tmplnamespace;
    9701             :     int         i_tmplinit;
    9702             :     int         i_tmpllexize;
    9703             : 
    9704         320 :     query = createPQExpBuffer();
    9705             : 
    9706         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
    9707             :                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
    9708             :                          "FROM pg_ts_template");
    9709             : 
    9710         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9711             : 
    9712         320 :     ntups = PQntuples(res);
    9713             : 
    9714         320 :     tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
    9715             : 
    9716         320 :     i_tableoid = PQfnumber(res, "tableoid");
    9717         320 :     i_oid = PQfnumber(res, "oid");
    9718         320 :     i_tmplname = PQfnumber(res, "tmplname");
    9719         320 :     i_tmplnamespace = PQfnumber(res, "tmplnamespace");
    9720         320 :     i_tmplinit = PQfnumber(res, "tmplinit");
    9721         320 :     i_tmpllexize = PQfnumber(res, "tmpllexize");
    9722             : 
    9723        2014 :     for (i = 0; i < ntups; i++)
    9724             :     {
    9725        1694 :         tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
    9726        1694 :         tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9727        1694 :         tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9728        1694 :         AssignDumpId(&tmplinfo[i].dobj);
    9729        1694 :         tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
    9730        3388 :         tmplinfo[i].dobj.namespace =
    9731        1694 :             findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
    9732        1694 :         tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
    9733        1694 :         tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
    9734             : 
    9735             :         /* Decide whether we want to dump it */
    9736        1694 :         selectDumpableObject(&(tmplinfo[i].dobj), fout);
    9737             :     }
    9738             : 
    9739         320 :     PQclear(res);
    9740             : 
    9741         320 :     destroyPQExpBuffer(query);
    9742         320 : }
    9743             : 
    9744             : /*
    9745             :  * getTSConfigurations:
    9746             :  *    get information about all text search configurations
    9747             :  */
    9748             : void
    9749         320 : getTSConfigurations(Archive *fout)
    9750             : {
    9751             :     PGresult   *res;
    9752             :     int         ntups;
    9753             :     int         i;
    9754             :     PQExpBuffer query;
    9755             :     TSConfigInfo *cfginfo;
    9756             :     int         i_tableoid;
    9757             :     int         i_oid;
    9758             :     int         i_cfgname;
    9759             :     int         i_cfgnamespace;
    9760             :     int         i_cfgowner;
    9761             :     int         i_cfgparser;
    9762             : 
    9763         320 :     query = createPQExpBuffer();
    9764             : 
    9765         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
    9766             :                          "cfgnamespace, cfgowner, cfgparser "
    9767             :                          "FROM pg_ts_config");
    9768             : 
    9769         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9770             : 
    9771         320 :     ntups = PQntuples(res);
    9772             : 
    9773         320 :     cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
    9774             : 
    9775         320 :     i_tableoid = PQfnumber(res, "tableoid");
    9776         320 :     i_oid = PQfnumber(res, "oid");
    9777         320 :     i_cfgname = PQfnumber(res, "cfgname");
    9778         320 :     i_cfgnamespace = PQfnumber(res, "cfgnamespace");
    9779         320 :     i_cfgowner = PQfnumber(res, "cfgowner");
    9780         320 :     i_cfgparser = PQfnumber(res, "cfgparser");
    9781             : 
    9782       10070 :     for (i = 0; i < ntups; i++)
    9783             :     {
    9784        9750 :         cfginfo[i].dobj.objType = DO_TSCONFIG;
    9785        9750 :         cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9786        9750 :         cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9787        9750 :         AssignDumpId(&cfginfo[i].dobj);
    9788        9750 :         cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
    9789       19500 :         cfginfo[i].dobj.namespace =
    9790        9750 :             findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
    9791        9750 :         cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
    9792        9750 :         cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
    9793             : 
    9794             :         /* Decide whether we want to dump it */
    9795        9750 :         selectDumpableObject(&(cfginfo[i].dobj), fout);
    9796             :     }
    9797             : 
    9798         320 :     PQclear(res);
    9799             : 
    9800         320 :     destroyPQExpBuffer(query);
    9801         320 : }
    9802             : 
    9803             : /*
    9804             :  * getForeignDataWrappers:
    9805             :  *    get information about all foreign-data wrappers in the system catalogs
    9806             :  */
    9807             : void
    9808         320 : getForeignDataWrappers(Archive *fout)
    9809             : {
    9810             :     PGresult   *res;
    9811             :     int         ntups;
    9812             :     int         i;
    9813             :     PQExpBuffer query;
    9814             :     FdwInfo    *fdwinfo;
    9815             :     int         i_tableoid;
    9816             :     int         i_oid;
    9817             :     int         i_fdwname;
    9818             :     int         i_fdwowner;
    9819             :     int         i_fdwhandler;
    9820             :     int         i_fdwvalidator;
    9821             :     int         i_fdwacl;
    9822             :     int         i_acldefault;
    9823             :     int         i_fdwoptions;
    9824             : 
    9825         320 :     query = createPQExpBuffer();
    9826             : 
    9827         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
    9828             :                          "fdwowner, "
    9829             :                          "fdwhandler::pg_catalog.regproc, "
    9830             :                          "fdwvalidator::pg_catalog.regproc, "
    9831             :                          "fdwacl, "
    9832             :                          "acldefault('F', fdwowner) AS acldefault, "
    9833             :                          "array_to_string(ARRAY("
    9834             :                          "SELECT quote_ident(option_name) || ' ' || "
    9835             :                          "quote_literal(option_value) "
    9836             :                          "FROM pg_options_to_table(fdwoptions) "
    9837             :                          "ORDER BY option_name"
    9838             :                          "), E',\n    ') AS fdwoptions "
    9839             :                          "FROM pg_foreign_data_wrapper");
    9840             : 
    9841         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9842             : 
    9843         320 :     ntups = PQntuples(res);
    9844             : 
    9845         320 :     fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
    9846             : 
    9847         320 :     i_tableoid = PQfnumber(res, "tableoid");
    9848         320 :     i_oid = PQfnumber(res, "oid");
    9849         320 :     i_fdwname = PQfnumber(res, "fdwname");
    9850         320 :     i_fdwowner = PQfnumber(res, "fdwowner");
    9851         320 :     i_fdwhandler = PQfnumber(res, "fdwhandler");
    9852         320 :     i_fdwvalidator = PQfnumber(res, "fdwvalidator");
    9853         320 :     i_fdwacl = PQfnumber(res, "fdwacl");
    9854         320 :     i_acldefault = PQfnumber(res, "acldefault");
    9855         320 :     i_fdwoptions = PQfnumber(res, "fdwoptions");
    9856             : 
    9857         466 :     for (i = 0; i < ntups; i++)
    9858             :     {
    9859         146 :         fdwinfo[i].dobj.objType = DO_FDW;
    9860         146 :         fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9861         146 :         fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9862         146 :         AssignDumpId(&fdwinfo[i].dobj);
    9863         146 :         fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
    9864         146 :         fdwinfo[i].dobj.namespace = NULL;
    9865         146 :         fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
    9866         146 :         fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9867         146 :         fdwinfo[i].dacl.privtype = 0;
    9868         146 :         fdwinfo[i].dacl.initprivs = NULL;
    9869         146 :         fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
    9870         146 :         fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
    9871         146 :         fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
    9872         146 :         fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
    9873             : 
    9874             :         /* Decide whether we want to dump it */
    9875         146 :         selectDumpableObject(&(fdwinfo[i].dobj), fout);
    9876             : 
    9877             :         /* Mark whether FDW has an ACL */
    9878         146 :         if (!PQgetisnull(res, i, i_fdwacl))
    9879          94 :             fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9880             :     }
    9881             : 
    9882         320 :     PQclear(res);
    9883             : 
    9884         320 :     destroyPQExpBuffer(query);
    9885         320 : }
    9886             : 
    9887             : /*
    9888             :  * getForeignServers:
    9889             :  *    get information about all foreign servers in the system catalogs
    9890             :  */
    9891             : void
    9892         320 : getForeignServers(Archive *fout)
    9893             : {
    9894             :     PGresult   *res;
    9895             :     int         ntups;
    9896             :     int         i;
    9897             :     PQExpBuffer query;
    9898             :     ForeignServerInfo *srvinfo;
    9899             :     int         i_tableoid;
    9900             :     int         i_oid;
    9901             :     int         i_srvname;
    9902             :     int         i_srvowner;
    9903             :     int         i_srvfdw;
    9904             :     int         i_srvtype;
    9905             :     int         i_srvversion;
    9906             :     int         i_srvacl;
    9907             :     int         i_acldefault;
    9908             :     int         i_srvoptions;
    9909             : 
    9910         320 :     query = createPQExpBuffer();
    9911             : 
    9912         320 :     appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
    9913             :                          "srvowner, "
    9914             :                          "srvfdw, srvtype, srvversion, srvacl, "
    9915             :                          "acldefault('S', srvowner) AS acldefault, "
    9916             :                          "array_to_string(ARRAY("
    9917             :                          "SELECT quote_ident(option_name) || ' ' || "
    9918             :                          "quote_literal(option_value) "
    9919             :                          "FROM pg_options_to_table(srvoptions) "
    9920             :                          "ORDER BY option_name"
    9921             :                          "), E',\n    ') AS srvoptions "
    9922             :                          "FROM pg_foreign_server");
    9923             : 
    9924         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
    9925             : 
    9926         320 :     ntups = PQntuples(res);
    9927             : 
    9928         320 :     srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
    9929             : 
    9930         320 :     i_tableoid = PQfnumber(res, "tableoid");
    9931         320 :     i_oid = PQfnumber(res, "oid");
    9932         320 :     i_srvname = PQfnumber(res, "srvname");
    9933         320 :     i_srvowner = PQfnumber(res, "srvowner");
    9934         320 :     i_srvfdw = PQfnumber(res, "srvfdw");
    9935         320 :     i_srvtype = PQfnumber(res, "srvtype");
    9936         320 :     i_srvversion = PQfnumber(res, "srvversion");
    9937         320 :     i_srvacl = PQfnumber(res, "srvacl");
    9938         320 :     i_acldefault = PQfnumber(res, "acldefault");
    9939         320 :     i_srvoptions = PQfnumber(res, "srvoptions");
    9940             : 
    9941         474 :     for (i = 0; i < ntups; i++)
    9942             :     {
    9943         154 :         srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
    9944         154 :         srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
    9945         154 :         srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
    9946         154 :         AssignDumpId(&srvinfo[i].dobj);
    9947         154 :         srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
    9948         154 :         srvinfo[i].dobj.namespace = NULL;
    9949         154 :         srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
    9950         154 :         srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
    9951         154 :         srvinfo[i].dacl.privtype = 0;
    9952         154 :         srvinfo[i].dacl.initprivs = NULL;
    9953         154 :         srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
    9954         154 :         srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
    9955         154 :         srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
    9956         154 :         srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
    9957         154 :         srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
    9958             : 
    9959             :         /* Decide whether we want to dump it */
    9960         154 :         selectDumpableObject(&(srvinfo[i].dobj), fout);
    9961             : 
    9962             :         /* Servers have user mappings */
    9963         154 :         srvinfo[i].dobj.components |= DUMP_COMPONENT_USERMAP;
    9964             : 
    9965             :         /* Mark whether server has an ACL */
    9966         154 :         if (!PQgetisnull(res, i, i_srvacl))
    9967          94 :             srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
    9968             :     }
    9969             : 
    9970         320 :     PQclear(res);
    9971             : 
    9972         320 :     destroyPQExpBuffer(query);
    9973         320 : }
    9974             : 
    9975             : /*
    9976             :  * getDefaultACLs:
    9977             :  *    get information about all default ACL information in the system catalogs
    9978             :  */
    9979             : void
    9980         320 : getDefaultACLs(Archive *fout)
    9981             : {
    9982         320 :     DumpOptions *dopt = fout->dopt;
    9983             :     DefaultACLInfo *daclinfo;
    9984             :     PQExpBuffer query;
    9985             :     PGresult   *res;
    9986             :     int         i_oid;
    9987             :     int         i_tableoid;
    9988             :     int         i_defaclrole;
    9989             :     int         i_defaclnamespace;
    9990             :     int         i_defaclobjtype;
    9991             :     int         i_defaclacl;
    9992             :     int         i_acldefault;
    9993             :     int         i,
    9994             :                 ntups;
    9995             : 
    9996         320 :     query = createPQExpBuffer();
    9997             : 
    9998             :     /*
    9999             :      * Global entries (with defaclnamespace=0) replace the hard-wired default
   10000             :      * ACL for their object type.  We should dump them as deltas from the
   10001             :      * default ACL, since that will be used as a starting point for
   10002             :      * interpreting the ALTER DEFAULT PRIVILEGES commands.  On the other hand,
   10003             :      * non-global entries can only add privileges not revoke them.  We must
   10004             :      * dump those as-is (i.e., as deltas from an empty ACL).
   10005             :      *
   10006             :      * We can use defaclobjtype as the object type for acldefault(), except
   10007             :      * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
   10008             :      * 's'.
   10009             :      */
   10010         320 :     appendPQExpBufferStr(query,
   10011             :                          "SELECT oid, tableoid, "
   10012             :                          "defaclrole, "
   10013             :                          "defaclnamespace, "
   10014             :                          "defaclobjtype, "
   10015             :                          "defaclacl, "
   10016             :                          "CASE WHEN defaclnamespace = 0 THEN "
   10017             :                          "acldefault(CASE WHEN defaclobjtype = 'S' "
   10018             :                          "THEN 's'::\"char\" ELSE defaclobjtype END, "
   10019             :                          "defaclrole) ELSE '{}' END AS acldefault "
   10020             :                          "FROM pg_default_acl");
   10021             : 
   10022         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10023             : 
   10024         320 :     ntups = PQntuples(res);
   10025             : 
   10026         320 :     daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
   10027             : 
   10028         320 :     i_oid = PQfnumber(res, "oid");
   10029         320 :     i_tableoid = PQfnumber(res, "tableoid");
   10030         320 :     i_defaclrole = PQfnumber(res, "defaclrole");
   10031         320 :     i_defaclnamespace = PQfnumber(res, "defaclnamespace");
   10032         320 :     i_defaclobjtype = PQfnumber(res, "defaclobjtype");
   10033         320 :     i_defaclacl = PQfnumber(res, "defaclacl");
   10034         320 :     i_acldefault = PQfnumber(res, "acldefault");
   10035             : 
   10036         696 :     for (i = 0; i < ntups; i++)
   10037             :     {
   10038         376 :         Oid         nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
   10039             : 
   10040         376 :         daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
   10041         376 :         daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
   10042         376 :         daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
   10043         376 :         AssignDumpId(&daclinfo[i].dobj);
   10044             :         /* cheesy ... is it worth coming up with a better object name? */
   10045         376 :         daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
   10046             : 
   10047         376 :         if (nspid != InvalidOid)
   10048         188 :             daclinfo[i].dobj.namespace = findNamespace(nspid);
   10049             :         else
   10050         188 :             daclinfo[i].dobj.namespace = NULL;
   10051             : 
   10052         376 :         daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
   10053         376 :         daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
   10054         376 :         daclinfo[i].dacl.privtype = 0;
   10055         376 :         daclinfo[i].dacl.initprivs = NULL;
   10056         376 :         daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
   10057         376 :         daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
   10058             : 
   10059             :         /* Default ACLs are ACLs, of course */
   10060         376 :         daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
   10061             : 
   10062             :         /* Decide whether we want to dump it */
   10063         376 :         selectDumpableDefaultACL(&(daclinfo[i]), dopt);
   10064             :     }
   10065             : 
   10066         320 :     PQclear(res);
   10067             : 
   10068         320 :     destroyPQExpBuffer(query);
   10069         320 : }
   10070             : 
   10071             : /*
   10072             :  * getRoleName -- look up the name of a role, given its OID
   10073             :  *
   10074             :  * In current usage, we don't expect failures, so error out for a bad OID.
   10075             :  */
   10076             : static const char *
   10077     1006672 : getRoleName(const char *roleoid_str)
   10078             : {
   10079     1006672 :     Oid         roleoid = atooid(roleoid_str);
   10080             : 
   10081             :     /*
   10082             :      * Do binary search to find the appropriate item.
   10083             :      */
   10084     1006672 :     if (nrolenames > 0)
   10085             :     {
   10086     1006672 :         RoleNameItem *low = &rolenames[0];
   10087     1006672 :         RoleNameItem *high = &rolenames[nrolenames - 1];
   10088             : 
   10089     4027094 :         while (low <= high)
   10090             :         {
   10091     4027094 :             RoleNameItem *middle = low + (high - low) / 2;
   10092             : 
   10093     4027094 :             if (roleoid < middle->roleoid)
   10094     3017806 :                 high = middle - 1;
   10095     1009288 :             else if (roleoid > middle->roleoid)
   10096        2616 :                 low = middle + 1;
   10097             :             else
   10098     1006672 :                 return middle->rolename; /* found a match */
   10099             :         }
   10100             :     }
   10101             : 
   10102           0 :     pg_fatal("role with OID %u does not exist", roleoid);
   10103             :     return NULL;                /* keep compiler quiet */
   10104             : }
   10105             : 
   10106             : /*
   10107             :  * collectRoleNames --
   10108             :  *
   10109             :  * Construct a table of all known roles.
   10110             :  * The table is sorted by OID for speed in lookup.
   10111             :  */
   10112             : static void
   10113         322 : collectRoleNames(Archive *fout)
   10114             : {
   10115             :     PGresult   *res;
   10116             :     const char *query;
   10117             :     int         i;
   10118             : 
   10119         322 :     query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
   10120             : 
   10121         322 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   10122             : 
   10123         322 :     nrolenames = PQntuples(res);
   10124             : 
   10125         322 :     rolenames = (RoleNameItem *) pg_malloc(nrolenames * sizeof(RoleNameItem));
   10126             : 
   10127        6212 :     for (i = 0; i < nrolenames; i++)
   10128             :     {
   10129        5890 :         rolenames[i].roleoid = atooid(PQgetvalue(res, i, 0));
   10130        5890 :         rolenames[i].rolename = pg_strdup(PQgetvalue(res, i, 1));
   10131             :     }
   10132             : 
   10133         322 :     PQclear(res);
   10134         322 : }
   10135             : 
   10136             : /*
   10137             :  * getAdditionalACLs
   10138             :  *
   10139             :  * We have now created all the DumpableObjects, and collected the ACL data
   10140             :  * that appears in the directly-associated catalog entries.  However, there's
   10141             :  * more ACL-related info to collect.  If any of a table's columns have ACLs,
   10142             :  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
   10143             :  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
   10144             :  * Also, in versions having the pg_init_privs catalog, read that and load the
   10145             :  * information into the relevant DumpableObjects.
   10146             :  */
   10147             : static void
   10148         316 : getAdditionalACLs(Archive *fout)
   10149             : {
   10150         316 :     PQExpBuffer query = createPQExpBuffer();
   10151             :     PGresult   *res;
   10152             :     int         ntups,
   10153             :                 i;
   10154             : 
   10155             :     /* Check for per-column ACLs */
   10156         316 :     appendPQExpBufferStr(query,
   10157             :                          "SELECT DISTINCT attrelid FROM pg_attribute "
   10158             :                          "WHERE attacl IS NOT NULL");
   10159             : 
   10160         316 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10161             : 
   10162         316 :     ntups = PQntuples(res);
   10163         984 :     for (i = 0; i < ntups; i++)
   10164             :     {
   10165         668 :         Oid         relid = atooid(PQgetvalue(res, i, 0));
   10166             :         TableInfo  *tblinfo;
   10167             : 
   10168         668 :         tblinfo = findTableByOid(relid);
   10169             :         /* OK to ignore tables we haven't got a DumpableObject for */
   10170         668 :         if (tblinfo)
   10171             :         {
   10172         668 :             tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
   10173         668 :             tblinfo->hascolumnACLs = true;
   10174             :         }
   10175             :     }
   10176         316 :     PQclear(res);
   10177             : 
   10178             :     /* Fetch initial-privileges data */
   10179         316 :     if (fout->remoteVersion >= 90600)
   10180             :     {
   10181         316 :         printfPQExpBuffer(query,
   10182             :                           "SELECT objoid, classoid, objsubid, privtype, initprivs "
   10183             :                           "FROM pg_init_privs");
   10184             : 
   10185         316 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10186             : 
   10187         316 :         ntups = PQntuples(res);
   10188       72032 :         for (i = 0; i < ntups; i++)
   10189             :         {
   10190       71716 :             Oid         objoid = atooid(PQgetvalue(res, i, 0));
   10191       71716 :             Oid         classoid = atooid(PQgetvalue(res, i, 1));
   10192       71716 :             int         objsubid = atoi(PQgetvalue(res, i, 2));
   10193       71716 :             char        privtype = *(PQgetvalue(res, i, 3));
   10194       71716 :             char       *initprivs = PQgetvalue(res, i, 4);
   10195             :             CatalogId   objId;
   10196             :             DumpableObject *dobj;
   10197             : 
   10198       71716 :             objId.tableoid = classoid;
   10199       71716 :             objId.oid = objoid;
   10200       71716 :             dobj = findObjectByCatalogId(objId);
   10201             :             /* OK to ignore entries we haven't got a DumpableObject for */
   10202       71716 :             if (dobj)
   10203             :             {
   10204             :                 /* Cope with sub-object initprivs */
   10205       51584 :                 if (objsubid != 0)
   10206             :                 {
   10207        5420 :                     if (dobj->objType == DO_TABLE)
   10208             :                     {
   10209             :                         /* For a column initprivs, set the table's ACL flags */
   10210        5420 :                         dobj->components |= DUMP_COMPONENT_ACL;
   10211        5420 :                         ((TableInfo *) dobj)->hascolumnACLs = true;
   10212             :                     }
   10213             :                     else
   10214           0 :                         pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10215             :                                        classoid, objoid, objsubid);
   10216        5728 :                     continue;
   10217             :                 }
   10218             : 
   10219             :                 /*
   10220             :                  * We ignore any pg_init_privs.initprivs entry for the public
   10221             :                  * schema, as explained in getNamespaces().
   10222             :                  */
   10223       46164 :                 if (dobj->objType == DO_NAMESPACE &&
   10224         624 :                     strcmp(dobj->name, "public") == 0)
   10225         308 :                     continue;
   10226             : 
   10227             :                 /* Else it had better be of a type we think has ACLs */
   10228       45856 :                 if (dobj->objType == DO_NAMESPACE ||
   10229       45540 :                     dobj->objType == DO_TYPE ||
   10230       45492 :                     dobj->objType == DO_FUNC ||
   10231       45304 :                     dobj->objType == DO_AGG ||
   10232       45256 :                     dobj->objType == DO_TABLE ||
   10233           0 :                     dobj->objType == DO_PROCLANG ||
   10234           0 :                     dobj->objType == DO_FDW ||
   10235           0 :                     dobj->objType == DO_FOREIGN_SERVER)
   10236       45856 :                 {
   10237       45856 :                     DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
   10238             : 
   10239       45856 :                     daobj->dacl.privtype = privtype;
   10240       45856 :                     daobj->dacl.initprivs = pstrdup(initprivs);
   10241             :                 }
   10242             :                 else
   10243           0 :                     pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
   10244             :                                    classoid, objoid, objsubid);
   10245             :             }
   10246             :         }
   10247         316 :         PQclear(res);
   10248             :     }
   10249             : 
   10250         316 :     destroyPQExpBuffer(query);
   10251         316 : }
   10252             : 
   10253             : /*
   10254             :  * dumpCommentExtended --
   10255             :  *
   10256             :  * This routine is used to dump any comments associated with the
   10257             :  * object handed to this routine. The routine takes the object type
   10258             :  * and object name (ready to print, except for schema decoration), plus
   10259             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   10260             :  * plus catalog ID and subid which are the lookup key for pg_description,
   10261             :  * plus the dump ID for the object (for setting a dependency).
   10262             :  * If a matching pg_description entry is found, it is dumped.
   10263             :  *
   10264             :  * Note: in some cases, such as comments for triggers and rules, the "type"
   10265             :  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
   10266             :  * but it doesn't seem worth complicating the API for all callers to make
   10267             :  * it cleaner.
   10268             :  *
   10269             :  * Note: although this routine takes a dumpId for dependency purposes,
   10270             :  * that purpose is just to mark the dependency in the emitted dump file
   10271             :  * for possible future use by pg_restore.  We do NOT use it for determining
   10272             :  * ordering of the comment in the dump file, because this routine is called
   10273             :  * after dependency sorting occurs.  This routine should be called just after
   10274             :  * calling ArchiveEntry() for the specified object.
   10275             :  */
   10276             : static void
   10277       12598 : dumpCommentExtended(Archive *fout, const char *type,
   10278             :                     const char *name, const char *namespace,
   10279             :                     const char *owner, CatalogId catalogId,
   10280             :                     int subid, DumpId dumpId,
   10281             :                     const char *initdb_comment)
   10282             : {
   10283       12598 :     DumpOptions *dopt = fout->dopt;
   10284             :     CommentItem *comments;
   10285             :     int         ncomments;
   10286             : 
   10287             :     /* do nothing, if --no-comments is supplied */
   10288       12598 :     if (dopt->no_comments)
   10289           0 :         return;
   10290             : 
   10291             :     /* Comments are schema not data ... except LO comments are data */
   10292       12598 :     if (strcmp(type, "LARGE OBJECT") != 0)
   10293             :     {
   10294       12496 :         if (!dopt->dumpSchema)
   10295           0 :             return;
   10296             :     }
   10297             :     else
   10298             :     {
   10299             :         /* We do dump LO comments in binary-upgrade mode */
   10300         102 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   10301           0 :             return;
   10302             :     }
   10303             : 
   10304             :     /* Search for comments associated with catalogId, using table */
   10305       12598 :     ncomments = findComments(catalogId.tableoid, catalogId.oid,
   10306             :                              &comments);
   10307             : 
   10308             :     /* Is there one matching the subid? */
   10309       12598 :     while (ncomments > 0)
   10310             :     {
   10311       12512 :         if (comments->objsubid == subid)
   10312       12512 :             break;
   10313           0 :         comments++;
   10314           0 :         ncomments--;
   10315             :     }
   10316             : 
   10317       12598 :     if (initdb_comment != NULL)
   10318             :     {
   10319             :         static CommentItem empty_comment = {.descr = ""};
   10320             : 
   10321             :         /*
   10322             :          * initdb creates this object with a comment.  Skip dumping the
   10323             :          * initdb-provided comment, which would complicate matters for
   10324             :          * non-superuser use of pg_dump.  When the DBA has removed initdb's
   10325             :          * comment, replicate that.
   10326             :          */
   10327         222 :         if (ncomments == 0)
   10328             :         {
   10329           8 :             comments = &empty_comment;
   10330           8 :             ncomments = 1;
   10331             :         }
   10332         214 :         else if (strcmp(comments->descr, initdb_comment) == 0)
   10333         214 :             ncomments = 0;
   10334             :     }
   10335             : 
   10336             :     /* If a comment exists, build COMMENT ON statement */
   10337       12598 :     if (ncomments > 0)
   10338             :     {
   10339       12306 :         PQExpBuffer query = createPQExpBuffer();
   10340       12306 :         PQExpBuffer tag = createPQExpBuffer();
   10341             : 
   10342       12306 :         appendPQExpBuffer(query, "COMMENT ON %s ", type);
   10343       12306 :         if (namespace && *namespace)
   10344       12000 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   10345       12306 :         appendPQExpBuffer(query, "%s IS ", name);
   10346       12306 :         appendStringLiteralAH(query, comments->descr, fout);
   10347       12306 :         appendPQExpBufferStr(query, ";\n");
   10348             : 
   10349       12306 :         appendPQExpBuffer(tag, "%s %s", type, name);
   10350             : 
   10351             :         /*
   10352             :          * We mark comments as SECTION_NONE because they really belong in the
   10353             :          * same section as their parent, whether that is pre-data or
   10354             :          * post-data.
   10355             :          */
   10356       12306 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10357       12306 :                      ARCHIVE_OPTS(.tag = tag->data,
   10358             :                                   .namespace = namespace,
   10359             :                                   .owner = owner,
   10360             :                                   .description = "COMMENT",
   10361             :                                   .section = SECTION_NONE,
   10362             :                                   .createStmt = query->data,
   10363             :                                   .deps = &dumpId,
   10364             :                                   .nDeps = 1));
   10365             : 
   10366       12306 :         destroyPQExpBuffer(query);
   10367       12306 :         destroyPQExpBuffer(tag);
   10368             :     }
   10369             : }
   10370             : 
   10371             : /*
   10372             :  * dumpComment --
   10373             :  *
   10374             :  * Typical simplification of the above function.
   10375             :  */
   10376             : static inline void
   10377       12338 : dumpComment(Archive *fout, const char *type,
   10378             :             const char *name, const char *namespace,
   10379             :             const char *owner, CatalogId catalogId,
   10380             :             int subid, DumpId dumpId)
   10381             : {
   10382       12338 :     dumpCommentExtended(fout, type, name, namespace, owner,
   10383             :                         catalogId, subid, dumpId, NULL);
   10384       12338 : }
   10385             : 
   10386             : /*
   10387             :  * Tabular description of the parameters to pg_restore_relation_stats()
   10388             :  * param_name, param_type
   10389             :  */
   10390             : static const char *rel_stats_arginfo[][2] = {
   10391             :     {"relation", "regclass"},
   10392             :     {"version", "integer"},
   10393             :     {"relpages", "integer"},
   10394             :     {"reltuples", "real"},
   10395             :     {"relallvisible", "integer"},
   10396             : };
   10397             : 
   10398             : /*
   10399             :  * Tabular description of the parameters to pg_restore_attribute_stats()
   10400             :  * param_name, param_type
   10401             :  */
   10402             : static const char *att_stats_arginfo[][2] = {
   10403             :     {"relation", "regclass"},
   10404             :     {"attname", "name"},
   10405             :     {"inherited", "boolean"},
   10406             :     {"version", "integer"},
   10407             :     {"null_frac", "float4"},
   10408             :     {"avg_width", "integer"},
   10409             :     {"n_distinct", "float4"},
   10410             :     {"most_common_vals", "text"},
   10411             :     {"most_common_freqs", "float4[]"},
   10412             :     {"histogram_bounds", "text"},
   10413             :     {"correlation", "float4"},
   10414             :     {"most_common_elems", "text"},
   10415             :     {"most_common_elem_freqs", "float4[]"},
   10416             :     {"elem_count_histogram", "float4[]"},
   10417             :     {"range_length_histogram", "text"},
   10418             :     {"range_empty_frac", "float4"},
   10419             :     {"range_bounds_histogram", "text"},
   10420             : };
   10421             : 
   10422             : /*
   10423             :  * getRelStatsExportQuery --
   10424             :  *
   10425             :  * Generate a query that will fetch all relation (e.g. pg_class)
   10426             :  * stats for a given relation.
   10427             :  */
   10428             : static void
   10429       11898 : getRelStatsExportQuery(PQExpBuffer query, Archive *fout,
   10430             :                        const char *schemaname, const char *relname)
   10431             : {
   10432       11898 :     resetPQExpBuffer(query);
   10433       11898 :     appendPQExpBufferStr(query,
   10434             :                          "SELECT c.oid::regclass AS relation, "
   10435             :                          "current_setting('server_version_num') AS version, "
   10436             :                          "c.relpages, c.reltuples, c.relallvisible "
   10437             :                          "FROM pg_class c "
   10438             :                          "JOIN pg_namespace n "
   10439             :                          "ON n.oid = c.relnamespace "
   10440             :                          "WHERE n.nspname = ");
   10441       11898 :     appendStringLiteralAH(query, schemaname, fout);
   10442       11898 :     appendPQExpBufferStr(query, " AND c.relname = ");
   10443       11898 :     appendStringLiteralAH(query, relname, fout);
   10444       11898 : }
   10445             : 
   10446             : /*
   10447             :  * getAttStatsExportQuery --
   10448             :  *
   10449             :  * Generate a query that will fetch all attribute (e.g. pg_statistic)
   10450             :  * stats for a given relation.
   10451             :  */
   10452             : static void
   10453       11898 : getAttStatsExportQuery(PQExpBuffer query, Archive *fout,
   10454             :                        const char *schemaname, const char *relname)
   10455             : {
   10456       11898 :     resetPQExpBuffer(query);
   10457       11898 :     appendPQExpBufferStr(query,
   10458             :                          "SELECT c.oid::regclass AS relation, "
   10459             :                          "s.attname,"
   10460             :                          "s.inherited,"
   10461             :                          "current_setting('server_version_num') AS version, "
   10462             :                          "s.null_frac,"
   10463             :                          "s.avg_width,"
   10464             :                          "s.n_distinct,"
   10465             :                          "s.most_common_vals,"
   10466             :                          "s.most_common_freqs,"
   10467             :                          "s.histogram_bounds,"
   10468             :                          "s.correlation,"
   10469             :                          "s.most_common_elems,"
   10470             :                          "s.most_common_elem_freqs,"
   10471             :                          "s.elem_count_histogram,");
   10472             : 
   10473       11898 :     if (fout->remoteVersion >= 170000)
   10474       11898 :         appendPQExpBufferStr(query,
   10475             :                              "s.range_length_histogram,"
   10476             :                              "s.range_empty_frac,"
   10477             :                              "s.range_bounds_histogram ");
   10478             :     else
   10479           0 :         appendPQExpBufferStr(query,
   10480             :                              "NULL AS range_length_histogram,"
   10481             :                              "NULL AS range_empty_frac,"
   10482             :                              "NULL AS range_bounds_histogram ");
   10483             : 
   10484       11898 :     appendPQExpBufferStr(query,
   10485             :                          "FROM pg_stats s "
   10486             :                          "JOIN pg_namespace n "
   10487             :                          "ON n.nspname = s.schemaname "
   10488             :                          "JOIN pg_class c "
   10489             :                          "ON c.relname = s.tablename "
   10490             :                          "AND c.relnamespace = n.oid "
   10491             :                          "WHERE s.schemaname = ");
   10492       11898 :     appendStringLiteralAH(query, schemaname, fout);
   10493       11898 :     appendPQExpBufferStr(query, " AND s.tablename = ");
   10494       11898 :     appendStringLiteralAH(query, relname, fout);
   10495       11898 :     appendPQExpBufferStr(query, " ORDER BY s.attname, s.inherited");
   10496       11898 : }
   10497             : 
   10498             : 
   10499             : /*
   10500             :  * appendNamedArgument --
   10501             :  *
   10502             :  * Convenience routine for constructing parameters of the form:
   10503             :  * 'paraname', 'value'::type
   10504             :  */
   10505             : static void
   10506      119394 : appendNamedArgument(PQExpBuffer out, Archive *fout, const char *argname,
   10507             :                     const char *argval, const char *argtype)
   10508             : {
   10509      119394 :     appendPQExpBufferStr(out, "\t");
   10510             : 
   10511      119394 :     appendStringLiteralAH(out, argname, fout);
   10512      119394 :     appendPQExpBufferStr(out, ", ");
   10513             : 
   10514      119394 :     appendStringLiteralAH(out, argval, fout);
   10515      119394 :     appendPQExpBuffer(out, "::%s", argtype);
   10516      119394 : }
   10517             : 
   10518             : /*
   10519             :  * appendRelStatsImport --
   10520             :  *
   10521             :  * Append a formatted pg_restore_relation_stats statement.
   10522             :  */
   10523             : static void
   10524       11898 : appendRelStatsImport(PQExpBuffer out, Archive *fout, PGresult *res)
   10525             : {
   10526       11898 :     const char *sep = "";
   10527             : 
   10528       11898 :     if (PQntuples(res) == 0)
   10529           0 :         return;
   10530             : 
   10531       11898 :     appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_relation_stats(\n");
   10532             : 
   10533       71388 :     for (int argno = 0; argno < lengthof(rel_stats_arginfo); argno++)
   10534             :     {
   10535       59490 :         const char *argname = rel_stats_arginfo[argno][0];
   10536       59490 :         const char *argtype = rel_stats_arginfo[argno][1];
   10537       59490 :         int         fieldno = PQfnumber(res, argname);
   10538             : 
   10539       59490 :         if (fieldno < 0)
   10540           0 :             pg_fatal("relation stats export query missing field '%s'",
   10541             :                      argname);
   10542             : 
   10543       59490 :         if (PQgetisnull(res, 0, fieldno))
   10544           0 :             continue;
   10545             : 
   10546       59490 :         appendPQExpBufferStr(out, sep);
   10547       59490 :         appendNamedArgument(out, fout, argname, PQgetvalue(res, 0, fieldno), argtype);
   10548             : 
   10549       59490 :         sep = ",\n";
   10550             :     }
   10551       11898 :     appendPQExpBufferStr(out, "\n);\n");
   10552             : }
   10553             : 
   10554             : /*
   10555             :  * appendAttStatsImport --
   10556             :  *
   10557             :  * Append a series of formatted pg_restore_attribute_stats statements.
   10558             :  */
   10559             : static void
   10560       11898 : appendAttStatsImport(PQExpBuffer out, Archive *fout, PGresult *res)
   10561             : {
   10562       18140 :     for (int rownum = 0; rownum < PQntuples(res); rownum++)
   10563             :     {
   10564        6242 :         const char *sep = "";
   10565             : 
   10566        6242 :         appendPQExpBufferStr(out, "SELECT * FROM pg_catalog.pg_restore_attribute_stats(\n");
   10567      112356 :         for (int argno = 0; argno < lengthof(att_stats_arginfo); argno++)
   10568             :         {
   10569      106114 :             const char *argname = att_stats_arginfo[argno][0];
   10570      106114 :             const char *argtype = att_stats_arginfo[argno][1];
   10571      106114 :             int         fieldno = PQfnumber(res, argname);
   10572             : 
   10573      106114 :             if (fieldno < 0)
   10574           0 :                 pg_fatal("attribute stats export query missing field '%s'",
   10575             :                          argname);
   10576             : 
   10577      106114 :             if (PQgetisnull(res, rownum, fieldno))
   10578       46210 :                 continue;
   10579             : 
   10580       59904 :             appendPQExpBufferStr(out, sep);
   10581       59904 :             appendNamedArgument(out, fout, argname, PQgetvalue(res, rownum, fieldno), argtype);
   10582       59904 :             sep = ",\n";
   10583             :         }
   10584        6242 :         appendPQExpBufferStr(out, "\n);\n");
   10585             :     }
   10586       11898 : }
   10587             : 
   10588             : /*
   10589             :  * Decide which section to use based on the relkind of the parent object.
   10590             :  *
   10591             :  * NB: materialized views may be postponed from SECTION_PRE_DATA to
   10592             :  * SECTION_POST_DATA to resolve some kinds of dependency problems. If so, the
   10593             :  * matview stats will also be postponed to SECTION_POST_DATA. See
   10594             :  * repairMatViewBoundaryMultiLoop().
   10595             :  */
   10596             : static teSection
   10597       23726 : statisticsDumpSection(const RelStatsInfo *rsinfo)
   10598             : {
   10599       23726 :     switch (rsinfo->relkind)
   10600             :     {
   10601       15946 :         case RELKIND_RELATION:
   10602             :         case RELKIND_PARTITIONED_TABLE:
   10603             :         case RELKIND_MATVIEW:
   10604       15946 :             return SECTION_DATA;
   10605        7780 :         case RELKIND_INDEX:
   10606             :         case RELKIND_PARTITIONED_INDEX:
   10607        7780 :             return SECTION_POST_DATA;
   10608           0 :         default:
   10609           0 :             pg_fatal("cannot dump statistics for relation kind '%c'",
   10610             :                      rsinfo->relkind);
   10611             :     }
   10612             : 
   10613             :     return 0;                   /* keep compiler quiet */
   10614             : }
   10615             : 
   10616             : /*
   10617             :  * dumpRelationStats --
   10618             :  *
   10619             :  * Dump command to import stats into the relation on the new database.
   10620             :  */
   10621             : static void
   10622       11898 : dumpRelationStats(Archive *fout, const RelStatsInfo *rsinfo)
   10623             : {
   10624             :     PGresult   *res;
   10625             :     PQExpBuffer query;
   10626             :     PQExpBuffer out;
   10627             :     PQExpBuffer tag;
   10628       11898 :     DumpableObject *dobj = (DumpableObject *) &rsinfo->dobj;
   10629       11898 :     DumpId     *deps = NULL;
   10630       11898 :     int         ndeps = 0;
   10631             : 
   10632             :     /* nothing to do if we are not dumping statistics */
   10633       11898 :     if (!fout->dopt->dumpStatistics)
   10634           0 :         return;
   10635             : 
   10636             :     /* dependent on the relation definition, if doing schema */
   10637       11898 :     if (fout->dopt->dumpSchema)
   10638             :     {
   10639       11520 :         deps = dobj->dependencies;
   10640       11520 :         ndeps = dobj->nDeps;
   10641             :     }
   10642             : 
   10643       11898 :     tag = createPQExpBuffer();
   10644       11898 :     appendPQExpBufferStr(tag, fmtId(dobj->name));
   10645             : 
   10646       11898 :     query = createPQExpBuffer();
   10647       11898 :     out = createPQExpBuffer();
   10648             : 
   10649       11898 :     getRelStatsExportQuery(query, fout, dobj->namespace->dobj.name,
   10650       11898 :                            dobj->name);
   10651       11898 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10652       11898 :     appendRelStatsImport(out, fout, res);
   10653       11898 :     PQclear(res);
   10654             : 
   10655       11898 :     getAttStatsExportQuery(query, fout, dobj->namespace->dobj.name,
   10656       11898 :                            dobj->name);
   10657       11898 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10658       11898 :     appendAttStatsImport(out, fout, res);
   10659       11898 :     PQclear(res);
   10660             : 
   10661       11898 :     ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10662       11898 :                  ARCHIVE_OPTS(.tag = tag->data,
   10663             :                               .namespace = dobj->namespace->dobj.name,
   10664             :                               .description = "STATISTICS DATA",
   10665             :                               .section = rsinfo->postponed_def ?
   10666             :                               SECTION_POST_DATA : statisticsDumpSection(rsinfo),
   10667             :                               .createStmt = out->data,
   10668             :                               .deps = deps,
   10669             :                               .nDeps = ndeps));
   10670             : 
   10671       11898 :     destroyPQExpBuffer(query);
   10672       11898 :     destroyPQExpBuffer(out);
   10673       11898 :     destroyPQExpBuffer(tag);
   10674             : }
   10675             : 
   10676             : /*
   10677             :  * dumpTableComment --
   10678             :  *
   10679             :  * As above, but dump comments for both the specified table (or view)
   10680             :  * and its columns.
   10681             :  */
   10682             : static void
   10683         156 : dumpTableComment(Archive *fout, const TableInfo *tbinfo,
   10684             :                  const char *reltypename)
   10685             : {
   10686         156 :     DumpOptions *dopt = fout->dopt;
   10687             :     CommentItem *comments;
   10688             :     int         ncomments;
   10689             :     PQExpBuffer query;
   10690             :     PQExpBuffer tag;
   10691             : 
   10692             :     /* do nothing, if --no-comments is supplied */
   10693         156 :     if (dopt->no_comments)
   10694           0 :         return;
   10695             : 
   10696             :     /* Comments are SCHEMA not data */
   10697         156 :     if (!dopt->dumpSchema)
   10698           0 :         return;
   10699             : 
   10700             :     /* Search for comments associated with relation, using table */
   10701         156 :     ncomments = findComments(tbinfo->dobj.catId.tableoid,
   10702             :                              tbinfo->dobj.catId.oid,
   10703             :                              &comments);
   10704             : 
   10705             :     /* If comments exist, build COMMENT ON statements */
   10706         156 :     if (ncomments <= 0)
   10707           0 :         return;
   10708             : 
   10709         156 :     query = createPQExpBuffer();
   10710         156 :     tag = createPQExpBuffer();
   10711             : 
   10712         448 :     while (ncomments > 0)
   10713             :     {
   10714         292 :         const char *descr = comments->descr;
   10715         292 :         int         objsubid = comments->objsubid;
   10716             : 
   10717         292 :         if (objsubid == 0)
   10718             :         {
   10719          68 :             resetPQExpBuffer(tag);
   10720          68 :             appendPQExpBuffer(tag, "%s %s", reltypename,
   10721          68 :                               fmtId(tbinfo->dobj.name));
   10722             : 
   10723          68 :             resetPQExpBuffer(query);
   10724          68 :             appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
   10725          68 :                               fmtQualifiedDumpable(tbinfo));
   10726          68 :             appendStringLiteralAH(query, descr, fout);
   10727          68 :             appendPQExpBufferStr(query, ";\n");
   10728             : 
   10729          68 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10730          68 :                          ARCHIVE_OPTS(.tag = tag->data,
   10731             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10732             :                                       .owner = tbinfo->rolname,
   10733             :                                       .description = "COMMENT",
   10734             :                                       .section = SECTION_NONE,
   10735             :                                       .createStmt = query->data,
   10736             :                                       .deps = &(tbinfo->dobj.dumpId),
   10737             :                                       .nDeps = 1));
   10738             :         }
   10739         224 :         else if (objsubid > 0 && objsubid <= tbinfo->numatts)
   10740             :         {
   10741         224 :             resetPQExpBuffer(tag);
   10742         224 :             appendPQExpBuffer(tag, "COLUMN %s.",
   10743         224 :                               fmtId(tbinfo->dobj.name));
   10744         224 :             appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
   10745             : 
   10746         224 :             resetPQExpBuffer(query);
   10747         224 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   10748         224 :                               fmtQualifiedDumpable(tbinfo));
   10749         224 :             appendPQExpBuffer(query, "%s IS ",
   10750         224 :                               fmtId(tbinfo->attnames[objsubid - 1]));
   10751         224 :             appendStringLiteralAH(query, descr, fout);
   10752         224 :             appendPQExpBufferStr(query, ";\n");
   10753             : 
   10754         224 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   10755         224 :                          ARCHIVE_OPTS(.tag = tag->data,
   10756             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   10757             :                                       .owner = tbinfo->rolname,
   10758             :                                       .description = "COMMENT",
   10759             :                                       .section = SECTION_NONE,
   10760             :                                       .createStmt = query->data,
   10761             :                                       .deps = &(tbinfo->dobj.dumpId),
   10762             :                                       .nDeps = 1));
   10763             :         }
   10764             : 
   10765         292 :         comments++;
   10766         292 :         ncomments--;
   10767             :     }
   10768             : 
   10769         156 :     destroyPQExpBuffer(query);
   10770         156 :     destroyPQExpBuffer(tag);
   10771             : }
   10772             : 
   10773             : /*
   10774             :  * findComments --
   10775             :  *
   10776             :  * Find the comment(s), if any, associated with the given object.  All the
   10777             :  * objsubid values associated with the given classoid/objoid are found with
   10778             :  * one search.
   10779             :  */
   10780             : static int
   10781       12822 : findComments(Oid classoid, Oid objoid, CommentItem **items)
   10782             : {
   10783       12822 :     CommentItem *middle = NULL;
   10784             :     CommentItem *low;
   10785             :     CommentItem *high;
   10786             :     int         nmatch;
   10787             : 
   10788             :     /*
   10789             :      * Do binary search to find some item matching the object.
   10790             :      */
   10791       12822 :     low = &comments[0];
   10792       12822 :     high = &comments[ncomments - 1];
   10793      127300 :     while (low <= high)
   10794             :     {
   10795      127214 :         middle = low + (high - low) / 2;
   10796             : 
   10797      127214 :         if (classoid < middle->classoid)
   10798       13222 :             high = middle - 1;
   10799      113992 :         else if (classoid > middle->classoid)
   10800       14082 :             low = middle + 1;
   10801       99910 :         else if (objoid < middle->objoid)
   10802       42188 :             high = middle - 1;
   10803       57722 :         else if (objoid > middle->objoid)
   10804       44986 :             low = middle + 1;
   10805             :         else
   10806       12736 :             break;              /* found a match */
   10807             :     }
   10808             : 
   10809       12822 :     if (low > high)              /* no matches */
   10810             :     {
   10811          86 :         *items = NULL;
   10812          86 :         return 0;
   10813             :     }
   10814             : 
   10815             :     /*
   10816             :      * Now determine how many items match the object.  The search loop
   10817             :      * invariant still holds: only items between low and high inclusive could
   10818             :      * match.
   10819             :      */
   10820       12736 :     nmatch = 1;
   10821       12736 :     while (middle > low)
   10822             :     {
   10823        6074 :         if (classoid != middle[-1].classoid ||
   10824        5846 :             objoid != middle[-1].objoid)
   10825             :             break;
   10826           0 :         middle--;
   10827           0 :         nmatch++;
   10828             :     }
   10829             : 
   10830       12736 :     *items = middle;
   10831             : 
   10832       12736 :     middle += nmatch;
   10833       12872 :     while (middle <= high)
   10834             :     {
   10835        6984 :         if (classoid != middle->classoid ||
   10836        6266 :             objoid != middle->objoid)
   10837             :             break;
   10838         136 :         middle++;
   10839         136 :         nmatch++;
   10840             :     }
   10841             : 
   10842       12736 :     return nmatch;
   10843             : }
   10844             : 
   10845             : /*
   10846             :  * collectComments --
   10847             :  *
   10848             :  * Construct a table of all comments available for database objects;
   10849             :  * also set the has-comment component flag for each relevant object.
   10850             :  *
   10851             :  * We used to do per-object queries for the comments, but it's much faster
   10852             :  * to pull them all over at once, and on most databases the memory cost
   10853             :  * isn't high.
   10854             :  *
   10855             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   10856             :  */
   10857             : static void
   10858         320 : collectComments(Archive *fout)
   10859             : {
   10860             :     PGresult   *res;
   10861             :     PQExpBuffer query;
   10862             :     int         i_description;
   10863             :     int         i_classoid;
   10864             :     int         i_objoid;
   10865             :     int         i_objsubid;
   10866             :     int         ntups;
   10867             :     int         i;
   10868             :     DumpableObject *dobj;
   10869             : 
   10870         320 :     query = createPQExpBuffer();
   10871             : 
   10872         320 :     appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
   10873             :                          "FROM pg_catalog.pg_description "
   10874             :                          "ORDER BY classoid, objoid, objsubid");
   10875             : 
   10876         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   10877             : 
   10878             :     /* Construct lookup table containing OIDs in numeric form */
   10879             : 
   10880         320 :     i_description = PQfnumber(res, "description");
   10881         320 :     i_classoid = PQfnumber(res, "classoid");
   10882         320 :     i_objoid = PQfnumber(res, "objoid");
   10883         320 :     i_objsubid = PQfnumber(res, "objsubid");
   10884             : 
   10885         320 :     ntups = PQntuples(res);
   10886             : 
   10887         320 :     comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
   10888         320 :     ncomments = 0;
   10889         320 :     dobj = NULL;
   10890             : 
   10891     1687546 :     for (i = 0; i < ntups; i++)
   10892             :     {
   10893             :         CatalogId   objId;
   10894             :         int         subid;
   10895             : 
   10896     1687226 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   10897     1687226 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   10898     1687226 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   10899             : 
   10900             :         /* We needn't remember comments that don't match any dumpable object */
   10901     1687226 :         if (dobj == NULL ||
   10902      607296 :             dobj->catId.tableoid != objId.tableoid ||
   10903      603290 :             dobj->catId.oid != objId.oid)
   10904     1687038 :             dobj = findObjectByCatalogId(objId);
   10905     1687226 :         if (dobj == NULL)
   10906     1079622 :             continue;
   10907             : 
   10908             :         /*
   10909             :          * Comments on columns of composite types are linked to the type's
   10910             :          * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
   10911             :          * in the type's own DumpableObject.
   10912             :          */
   10913      607604 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   10914         404 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   10915          94 :         {
   10916             :             TypeInfo   *cTypeInfo;
   10917             : 
   10918          94 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   10919          94 :             if (cTypeInfo)
   10920          94 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
   10921             :         }
   10922             :         else
   10923      607510 :             dobj->components |= DUMP_COMPONENT_COMMENT;
   10924             : 
   10925      607604 :         comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
   10926      607604 :         comments[ncomments].classoid = objId.tableoid;
   10927      607604 :         comments[ncomments].objoid = objId.oid;
   10928      607604 :         comments[ncomments].objsubid = subid;
   10929      607604 :         ncomments++;
   10930             :     }
   10931             : 
   10932         320 :     PQclear(res);
   10933         320 :     destroyPQExpBuffer(query);
   10934         320 : }
   10935             : 
   10936             : /*
   10937             :  * dumpDumpableObject
   10938             :  *
   10939             :  * This routine and its subsidiaries are responsible for creating
   10940             :  * ArchiveEntries (TOC objects) for each object to be dumped.
   10941             :  */
   10942             : static void
   10943     1187240 : dumpDumpableObject(Archive *fout, DumpableObject *dobj)
   10944             : {
   10945             :     /*
   10946             :      * Clear any dump-request bits for components that don't exist for this
   10947             :      * object.  (This makes it safe to initially use DUMP_COMPONENT_ALL as the
   10948             :      * request for every kind of object.)
   10949             :      */
   10950     1187240 :     dobj->dump &= dobj->components;
   10951             : 
   10952             :     /* Now, short-circuit if there's nothing to be done here. */
   10953     1187240 :     if (dobj->dump == 0)
   10954     1041708 :         return;
   10955             : 
   10956      145532 :     switch (dobj->objType)
   10957             :     {
   10958         834 :         case DO_NAMESPACE:
   10959         834 :             dumpNamespace(fout, (const NamespaceInfo *) dobj);
   10960         834 :             break;
   10961          38 :         case DO_EXTENSION:
   10962          38 :             dumpExtension(fout, (const ExtensionInfo *) dobj);
   10963          38 :             break;
   10964        1758 :         case DO_TYPE:
   10965        1758 :             dumpType(fout, (const TypeInfo *) dobj);
   10966        1758 :             break;
   10967         150 :         case DO_SHELL_TYPE:
   10968         150 :             dumpShellType(fout, (const ShellTypeInfo *) dobj);
   10969         150 :             break;
   10970        3696 :         case DO_FUNC:
   10971        3696 :             dumpFunc(fout, (const FuncInfo *) dobj);
   10972        3696 :             break;
   10973         588 :         case DO_AGG:
   10974         588 :             dumpAgg(fout, (const AggInfo *) dobj);
   10975         588 :             break;
   10976        5012 :         case DO_OPERATOR:
   10977        5012 :             dumpOpr(fout, (const OprInfo *) dobj);
   10978        5012 :             break;
   10979         168 :         case DO_ACCESS_METHOD:
   10980         168 :             dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
   10981         168 :             break;
   10982        1332 :         case DO_OPCLASS:
   10983        1332 :             dumpOpclass(fout, (const OpclassInfo *) dobj);
   10984        1332 :             break;
   10985        1106 :         case DO_OPFAMILY:
   10986        1106 :             dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
   10987        1106 :             break;
   10988        4944 :         case DO_COLLATION:
   10989        4944 :             dumpCollation(fout, (const CollInfo *) dobj);
   10990        4944 :             break;
   10991         848 :         case DO_CONVERSION:
   10992         848 :             dumpConversion(fout, (const ConvInfo *) dobj);
   10993         848 :             break;
   10994       52734 :         case DO_TABLE:
   10995       52734 :             dumpTable(fout, (const TableInfo *) dobj);
   10996       52734 :             break;
   10997        2582 :         case DO_TABLE_ATTACH:
   10998        2582 :             dumpTableAttach(fout, (const TableAttachInfo *) dobj);
   10999        2582 :             break;
   11000        2002 :         case DO_ATTRDEF:
   11001        2002 :             dumpAttrDef(fout, (const AttrDefInfo *) dobj);
   11002        2002 :             break;
   11003        5184 :         case DO_INDEX:
   11004        5184 :             dumpIndex(fout, (const IndxInfo *) dobj);
   11005        5184 :             break;
   11006        1160 :         case DO_INDEX_ATTACH:
   11007        1160 :             dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
   11008        1160 :             break;
   11009         278 :         case DO_STATSEXT:
   11010         278 :             dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
   11011         278 :             break;
   11012         784 :         case DO_REFRESH_MATVIEW:
   11013         784 :             refreshMatViewData(fout, (const TableDataInfo *) dobj);
   11014         784 :             break;
   11015        2330 :         case DO_RULE:
   11016        2330 :             dumpRule(fout, (const RuleInfo *) dobj);
   11017        2330 :             break;
   11018        1066 :         case DO_TRIGGER:
   11019        1066 :             dumpTrigger(fout, (const TriggerInfo *) dobj);
   11020        1066 :             break;
   11021          88 :         case DO_EVENT_TRIGGER:
   11022          88 :             dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
   11023          88 :             break;
   11024        4396 :         case DO_CONSTRAINT:
   11025        4396 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11026        4396 :             break;
   11027         360 :         case DO_FK_CONSTRAINT:
   11028         360 :             dumpConstraint(fout, (const ConstraintInfo *) dobj);
   11029         360 :             break;
   11030         172 :         case DO_PROCLANG:
   11031         172 :             dumpProcLang(fout, (const ProcLangInfo *) dobj);
   11032         172 :             break;
   11033         138 :         case DO_CAST:
   11034         138 :             dumpCast(fout, (const CastInfo *) dobj);
   11035         138 :             break;
   11036          88 :         case DO_TRANSFORM:
   11037          88 :             dumpTransform(fout, (const TransformInfo *) dobj);
   11038          88 :             break;
   11039         790 :         case DO_SEQUENCE_SET:
   11040         790 :             dumpSequenceData(fout, (const TableDataInfo *) dobj);
   11041         790 :             break;
   11042        7836 :         case DO_TABLE_DATA:
   11043        7836 :             dumpTableData(fout, (const TableDataInfo *) dobj);
   11044        7836 :             break;
   11045       26808 :         case DO_DUMMY_TYPE:
   11046             :             /* table rowtypes and array types are never dumped separately */
   11047       26808 :             break;
   11048          86 :         case DO_TSPARSER:
   11049          86 :             dumpTSParser(fout, (const TSParserInfo *) dobj);
   11050          86 :             break;
   11051         350 :         case DO_TSDICT:
   11052         350 :             dumpTSDictionary(fout, (const TSDictInfo *) dobj);
   11053         350 :             break;
   11054         110 :         case DO_TSTEMPLATE:
   11055         110 :             dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
   11056         110 :             break;
   11057         300 :         case DO_TSCONFIG:
   11058         300 :             dumpTSConfig(fout, (const TSConfigInfo *) dobj);
   11059         300 :             break;
   11060         108 :         case DO_FDW:
   11061         108 :             dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
   11062         108 :             break;
   11063         116 :         case DO_FOREIGN_SERVER:
   11064         116 :             dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
   11065         116 :             break;
   11066         316 :         case DO_DEFAULT_ACL:
   11067         316 :             dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
   11068         316 :             break;
   11069         154 :         case DO_LARGE_OBJECT:
   11070         154 :             dumpLO(fout, (const LoInfo *) dobj);
   11071         154 :             break;
   11072         154 :         case DO_LARGE_OBJECT_DATA:
   11073         154 :             if (dobj->dump & DUMP_COMPONENT_DATA)
   11074             :             {
   11075             :                 LoInfo     *loinfo;
   11076             :                 TocEntry   *te;
   11077             : 
   11078         154 :                 loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
   11079         154 :                 if (loinfo == NULL)
   11080           0 :                     pg_fatal("missing metadata for large objects \"%s\"",
   11081             :                              dobj->name);
   11082             : 
   11083         154 :                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
   11084         154 :                                   ARCHIVE_OPTS(.tag = dobj->name,
   11085             :                                                .owner = loinfo->rolname,
   11086             :                                                .description = "BLOBS",
   11087             :                                                .section = SECTION_DATA,
   11088             :                                                .deps = dobj->dependencies,
   11089             :                                                .nDeps = dobj->nDeps,
   11090             :                                                .dumpFn = dumpLOs,
   11091             :                                                .dumpArg = loinfo));
   11092             : 
   11093             :                 /*
   11094             :                  * Set the TocEntry's dataLength in case we are doing a
   11095             :                  * parallel dump and want to order dump jobs by table size.
   11096             :                  * (We need some size estimate for every TocEntry with a
   11097             :                  * DataDumper function.)  We don't currently have any cheap
   11098             :                  * way to estimate the size of LOs, but fortunately it doesn't
   11099             :                  * matter too much as long as we get large batches of LOs
   11100             :                  * processed reasonably early.  Assume 8K per blob.
   11101             :                  */
   11102         154 :                 te->dataLength = loinfo->numlos * (pgoff_t) 8192;
   11103             :             }
   11104         154 :             break;
   11105         694 :         case DO_POLICY:
   11106         694 :             dumpPolicy(fout, (const PolicyInfo *) dobj);
   11107         694 :             break;
   11108         392 :         case DO_PUBLICATION:
   11109         392 :             dumpPublication(fout, (const PublicationInfo *) dobj);
   11110         392 :             break;
   11111         546 :         case DO_PUBLICATION_REL:
   11112         546 :             dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
   11113         546 :             break;
   11114         156 :         case DO_PUBLICATION_TABLE_IN_SCHEMA:
   11115         156 :             dumpPublicationNamespace(fout,
   11116             :                                      (const PublicationSchemaInfo *) dobj);
   11117         156 :             break;
   11118         238 :         case DO_SUBSCRIPTION:
   11119         238 :             dumpSubscription(fout, (const SubscriptionInfo *) dobj);
   11120         238 :             break;
   11121           4 :         case DO_SUBSCRIPTION_REL:
   11122           4 :             dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
   11123           4 :             break;
   11124       11898 :         case DO_REL_STATS:
   11125       11898 :             dumpRelationStats(fout, (const RelStatsInfo *) dobj);
   11126       11898 :             break;
   11127         640 :         case DO_PRE_DATA_BOUNDARY:
   11128             :         case DO_POST_DATA_BOUNDARY:
   11129             :             /* never dumped, nothing to do */
   11130         640 :             break;
   11131             :     }
   11132             : }
   11133             : 
   11134             : /*
   11135             :  * dumpNamespace
   11136             :  *    writes out to fout the queries to recreate a user-defined namespace
   11137             :  */
   11138             : static void
   11139         834 : dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
   11140             : {
   11141         834 :     DumpOptions *dopt = fout->dopt;
   11142             :     PQExpBuffer q;
   11143             :     PQExpBuffer delq;
   11144             :     char       *qnspname;
   11145             : 
   11146             :     /* Do nothing if not dumping schema */
   11147         834 :     if (!dopt->dumpSchema)
   11148          56 :         return;
   11149             : 
   11150         778 :     q = createPQExpBuffer();
   11151         778 :     delq = createPQExpBuffer();
   11152             : 
   11153         778 :     qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
   11154             : 
   11155         778 :     if (nspinfo->create)
   11156             :     {
   11157         528 :         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
   11158         528 :         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
   11159             :     }
   11160             :     else
   11161             :     {
   11162             :         /* see selectDumpableNamespace() */
   11163         250 :         appendPQExpBufferStr(delq,
   11164             :                              "-- *not* dropping schema, since initdb creates it\n");
   11165         250 :         appendPQExpBufferStr(q,
   11166             :                              "-- *not* creating schema, since initdb creates it\n");
   11167             :     }
   11168             : 
   11169         778 :     if (dopt->binary_upgrade)
   11170          92 :         binary_upgrade_extension_member(q, &nspinfo->dobj,
   11171             :                                         "SCHEMA", qnspname, NULL);
   11172             : 
   11173         778 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11174         342 :         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
   11175         342 :                      ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
   11176             :                                   .owner = nspinfo->rolname,
   11177             :                                   .description = "SCHEMA",
   11178             :                                   .section = SECTION_PRE_DATA,
   11179             :                                   .createStmt = q->data,
   11180             :                                   .dropStmt = delq->data));
   11181             : 
   11182             :     /* Dump Schema Comments and Security Labels */
   11183         778 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11184             :     {
   11185         260 :         const char *initdb_comment = NULL;
   11186             : 
   11187         260 :         if (!nspinfo->create && strcmp(qnspname, "public") == 0)
   11188         222 :             initdb_comment = "standard public schema";
   11189         260 :         dumpCommentExtended(fout, "SCHEMA", qnspname,
   11190             :                             NULL, nspinfo->rolname,
   11191             :                             nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
   11192             :                             initdb_comment);
   11193             :     }
   11194             : 
   11195         778 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11196           0 :         dumpSecLabel(fout, "SCHEMA", qnspname,
   11197             :                      NULL, nspinfo->rolname,
   11198             :                      nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
   11199             : 
   11200         778 :     if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11201         610 :         dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
   11202             :                 qnspname, NULL, NULL,
   11203             :                 NULL, nspinfo->rolname, &nspinfo->dacl);
   11204             : 
   11205         778 :     free(qnspname);
   11206             : 
   11207         778 :     destroyPQExpBuffer(q);
   11208         778 :     destroyPQExpBuffer(delq);
   11209             : }
   11210             : 
   11211             : /*
   11212             :  * dumpExtension
   11213             :  *    writes out to fout the queries to recreate an extension
   11214             :  */
   11215             : static void
   11216          38 : dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
   11217             : {
   11218          38 :     DumpOptions *dopt = fout->dopt;
   11219             :     PQExpBuffer q;
   11220             :     PQExpBuffer delq;
   11221             :     char       *qextname;
   11222             : 
   11223             :     /* Do nothing if not dumping schema */
   11224          38 :     if (!dopt->dumpSchema)
   11225           2 :         return;
   11226             : 
   11227          36 :     q = createPQExpBuffer();
   11228          36 :     delq = createPQExpBuffer();
   11229             : 
   11230          36 :     qextname = pg_strdup(fmtId(extinfo->dobj.name));
   11231             : 
   11232          36 :     appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
   11233             : 
   11234          36 :     if (!dopt->binary_upgrade)
   11235             :     {
   11236             :         /*
   11237             :          * In a regular dump, we simply create the extension, intentionally
   11238             :          * not specifying a version, so that the destination installation's
   11239             :          * default version is used.
   11240             :          *
   11241             :          * Use of IF NOT EXISTS here is unlike our behavior for other object
   11242             :          * types; but there are various scenarios in which it's convenient to
   11243             :          * manually create the desired extension before restoring, so we
   11244             :          * prefer to allow it to exist already.
   11245             :          */
   11246          34 :         appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
   11247          34 :                           qextname, fmtId(extinfo->namespace));
   11248             :     }
   11249             :     else
   11250             :     {
   11251             :         /*
   11252             :          * In binary-upgrade mode, it's critical to reproduce the state of the
   11253             :          * database exactly, so our procedure is to create an empty extension,
   11254             :          * restore all the contained objects normally, and add them to the
   11255             :          * extension one by one.  This function performs just the first of
   11256             :          * those steps.  binary_upgrade_extension_member() takes care of
   11257             :          * adding member objects as they're created.
   11258             :          */
   11259             :         int         i;
   11260             :         int         n;
   11261             : 
   11262           2 :         appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
   11263             : 
   11264             :         /*
   11265             :          * We unconditionally create the extension, so we must drop it if it
   11266             :          * exists.  This could happen if the user deleted 'plpgsql' and then
   11267             :          * readded it, causing its oid to be greater than g_last_builtin_oid.
   11268             :          */
   11269           2 :         appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
   11270             : 
   11271           2 :         appendPQExpBufferStr(q,
   11272             :                              "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
   11273           2 :         appendStringLiteralAH(q, extinfo->dobj.name, fout);
   11274           2 :         appendPQExpBufferStr(q, ", ");
   11275           2 :         appendStringLiteralAH(q, extinfo->namespace, fout);
   11276           2 :         appendPQExpBufferStr(q, ", ");
   11277           2 :         appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
   11278           2 :         appendStringLiteralAH(q, extinfo->extversion, fout);
   11279           2 :         appendPQExpBufferStr(q, ", ");
   11280             : 
   11281             :         /*
   11282             :          * Note that we're pushing extconfig (an OID array) back into
   11283             :          * pg_extension exactly as-is.  This is OK because pg_class OIDs are
   11284             :          * preserved in binary upgrade.
   11285             :          */
   11286           2 :         if (strlen(extinfo->extconfig) > 2)
   11287           2 :             appendStringLiteralAH(q, extinfo->extconfig, fout);
   11288             :         else
   11289           0 :             appendPQExpBufferStr(q, "NULL");
   11290           2 :         appendPQExpBufferStr(q, ", ");
   11291           2 :         if (strlen(extinfo->extcondition) > 2)
   11292           2 :             appendStringLiteralAH(q, extinfo->extcondition, fout);
   11293             :         else
   11294           0 :             appendPQExpBufferStr(q, "NULL");
   11295           2 :         appendPQExpBufferStr(q, ", ");
   11296           2 :         appendPQExpBufferStr(q, "ARRAY[");
   11297           2 :         n = 0;
   11298           4 :         for (i = 0; i < extinfo->dobj.nDeps; i++)
   11299             :         {
   11300             :             DumpableObject *extobj;
   11301             : 
   11302           2 :             extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
   11303           2 :             if (extobj && extobj->objType == DO_EXTENSION)
   11304             :             {
   11305           0 :                 if (n++ > 0)
   11306           0 :                     appendPQExpBufferChar(q, ',');
   11307           0 :                 appendStringLiteralAH(q, extobj->name, fout);
   11308             :             }
   11309             :         }
   11310           2 :         appendPQExpBufferStr(q, "]::pg_catalog.text[]");
   11311           2 :         appendPQExpBufferStr(q, ");\n");
   11312             :     }
   11313             : 
   11314          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11315          36 :         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
   11316          36 :                      ARCHIVE_OPTS(.tag = extinfo->dobj.name,
   11317             :                                   .description = "EXTENSION",
   11318             :                                   .section = SECTION_PRE_DATA,
   11319             :                                   .createStmt = q->data,
   11320             :                                   .dropStmt = delq->data));
   11321             : 
   11322             :     /* Dump Extension Comments and Security Labels */
   11323          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11324          36 :         dumpComment(fout, "EXTENSION", qextname,
   11325             :                     NULL, "",
   11326             :                     extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11327             : 
   11328          36 :     if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11329           0 :         dumpSecLabel(fout, "EXTENSION", qextname,
   11330             :                      NULL, "",
   11331             :                      extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
   11332             : 
   11333          36 :     free(qextname);
   11334             : 
   11335          36 :     destroyPQExpBuffer(q);
   11336          36 :     destroyPQExpBuffer(delq);
   11337             : }
   11338             : 
   11339             : /*
   11340             :  * dumpType
   11341             :  *    writes out to fout the queries to recreate a user-defined type
   11342             :  */
   11343             : static void
   11344        1758 : dumpType(Archive *fout, const TypeInfo *tyinfo)
   11345             : {
   11346        1758 :     DumpOptions *dopt = fout->dopt;
   11347             : 
   11348             :     /* Do nothing if not dumping schema */
   11349        1758 :     if (!dopt->dumpSchema)
   11350          86 :         return;
   11351             : 
   11352             :     /* Dump out in proper style */
   11353        1672 :     if (tyinfo->typtype == TYPTYPE_BASE)
   11354         558 :         dumpBaseType(fout, tyinfo);
   11355        1114 :     else if (tyinfo->typtype == TYPTYPE_DOMAIN)
   11356         278 :         dumpDomain(fout, tyinfo);
   11357         836 :     else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
   11358         264 :         dumpCompositeType(fout, tyinfo);
   11359         572 :     else if (tyinfo->typtype == TYPTYPE_ENUM)
   11360         112 :         dumpEnumType(fout, tyinfo);
   11361         460 :     else if (tyinfo->typtype == TYPTYPE_RANGE)
   11362         232 :         dumpRangeType(fout, tyinfo);
   11363         228 :     else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
   11364          78 :         dumpUndefinedType(fout, tyinfo);
   11365             :     else
   11366         150 :         pg_log_warning("typtype of data type \"%s\" appears to be invalid",
   11367             :                        tyinfo->dobj.name);
   11368             : }
   11369             : 
   11370             : /*
   11371             :  * dumpEnumType
   11372             :  *    writes out to fout the queries to recreate a user-defined enum type
   11373             :  */
   11374             : static void
   11375         112 : dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
   11376             : {
   11377         112 :     DumpOptions *dopt = fout->dopt;
   11378         112 :     PQExpBuffer q = createPQExpBuffer();
   11379         112 :     PQExpBuffer delq = createPQExpBuffer();
   11380         112 :     PQExpBuffer query = createPQExpBuffer();
   11381             :     PGresult   *res;
   11382             :     int         num,
   11383             :                 i;
   11384             :     Oid         enum_oid;
   11385             :     char       *qtypname;
   11386             :     char       *qualtypname;
   11387             :     char       *label;
   11388             :     int         i_enumlabel;
   11389             :     int         i_oid;
   11390             : 
   11391         112 :     if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
   11392             :     {
   11393             :         /* Set up query for enum-specific details */
   11394          82 :         appendPQExpBufferStr(query,
   11395             :                              "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
   11396             :                              "SELECT oid, enumlabel "
   11397             :                              "FROM pg_catalog.pg_enum "
   11398             :                              "WHERE enumtypid = $1 "
   11399             :                              "ORDER BY enumsortorder");
   11400             : 
   11401          82 :         ExecuteSqlStatement(fout, query->data);
   11402             : 
   11403          82 :         fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
   11404             :     }
   11405             : 
   11406         112 :     printfPQExpBuffer(query,
   11407             :                       "EXECUTE dumpEnumType('%u')",
   11408             :                       tyinfo->dobj.catId.oid);
   11409             : 
   11410         112 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   11411             : 
   11412         112 :     num = PQntuples(res);
   11413             : 
   11414         112 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11415         112 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11416             : 
   11417             :     /*
   11418             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11419             :      * functions are generic and do not get dropped.
   11420             :      */
   11421         112 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11422             : 
   11423         112 :     if (dopt->binary_upgrade)
   11424          10 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11425             :                                                  tyinfo->dobj.catId.oid,
   11426             :                                                  false, false);
   11427             : 
   11428         112 :     appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
   11429             :                       qualtypname);
   11430             : 
   11431         112 :     if (!dopt->binary_upgrade)
   11432             :     {
   11433         102 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11434             : 
   11435             :         /* Labels with server-assigned oids */
   11436         740 :         for (i = 0; i < num; i++)
   11437             :         {
   11438         638 :             label = PQgetvalue(res, i, i_enumlabel);
   11439         638 :             if (i > 0)
   11440         536 :                 appendPQExpBufferChar(q, ',');
   11441         638 :             appendPQExpBufferStr(q, "\n    ");
   11442         638 :             appendStringLiteralAH(q, label, fout);
   11443             :         }
   11444             :     }
   11445             : 
   11446         112 :     appendPQExpBufferStr(q, "\n);\n");
   11447             : 
   11448         112 :     if (dopt->binary_upgrade)
   11449             :     {
   11450          10 :         i_oid = PQfnumber(res, "oid");
   11451          10 :         i_enumlabel = PQfnumber(res, "enumlabel");
   11452             : 
   11453             :         /* Labels with dump-assigned (preserved) oids */
   11454         116 :         for (i = 0; i < num; i++)
   11455             :         {
   11456         106 :             enum_oid = atooid(PQgetvalue(res, i, i_oid));
   11457         106 :             label = PQgetvalue(res, i, i_enumlabel);
   11458             : 
   11459         106 :             if (i == 0)
   11460          10 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
   11461         106 :             appendPQExpBuffer(q,
   11462             :                               "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
   11463             :                               enum_oid);
   11464         106 :             appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
   11465         106 :             appendStringLiteralAH(q, label, fout);
   11466         106 :             appendPQExpBufferStr(q, ";\n\n");
   11467             :         }
   11468             :     }
   11469             : 
   11470         112 :     if (dopt->binary_upgrade)
   11471          10 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11472             :                                         "TYPE", qtypname,
   11473          10 :                                         tyinfo->dobj.namespace->dobj.name);
   11474             : 
   11475         112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11476         112 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11477         112 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11478             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11479             :                                   .owner = tyinfo->rolname,
   11480             :                                   .description = "TYPE",
   11481             :                                   .section = SECTION_PRE_DATA,
   11482             :                                   .createStmt = q->data,
   11483             :                                   .dropStmt = delq->data));
   11484             : 
   11485             :     /* Dump Type Comments and Security Labels */
   11486         112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11487          68 :         dumpComment(fout, "TYPE", qtypname,
   11488          68 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11489             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11490             : 
   11491         112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11492           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11493           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11494             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11495             : 
   11496         112 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11497          68 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11498             :                 qtypname, NULL,
   11499          68 :                 tyinfo->dobj.namespace->dobj.name,
   11500             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11501             : 
   11502         112 :     PQclear(res);
   11503         112 :     destroyPQExpBuffer(q);
   11504         112 :     destroyPQExpBuffer(delq);
   11505         112 :     destroyPQExpBuffer(query);
   11506         112 :     free(qtypname);
   11507         112 :     free(qualtypname);
   11508         112 : }
   11509             : 
   11510             : /*
   11511             :  * dumpRangeType
   11512             :  *    writes out to fout the queries to recreate a user-defined range type
   11513             :  */
   11514             : static void
   11515         232 : dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
   11516             : {
   11517         232 :     DumpOptions *dopt = fout->dopt;
   11518         232 :     PQExpBuffer q = createPQExpBuffer();
   11519         232 :     PQExpBuffer delq = createPQExpBuffer();
   11520         232 :     PQExpBuffer query = createPQExpBuffer();
   11521             :     PGresult   *res;
   11522             :     Oid         collationOid;
   11523             :     char       *qtypname;
   11524             :     char       *qualtypname;
   11525             :     char       *procname;
   11526             : 
   11527         232 :     if (!fout->is_prepared[PREPQUERY_DUMPRANGETYPE])
   11528             :     {
   11529             :         /* Set up query for range-specific details */
   11530          84 :         appendPQExpBufferStr(query,
   11531             :                              "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
   11532             : 
   11533          84 :         appendPQExpBufferStr(query,
   11534             :                              "SELECT ");
   11535             : 
   11536          84 :         if (fout->remoteVersion >= 140000)
   11537          84 :             appendPQExpBufferStr(query,
   11538             :                                  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
   11539             :         else
   11540           0 :             appendPQExpBufferStr(query,
   11541             :                                  "NULL AS rngmultitype, ");
   11542             : 
   11543          84 :         appendPQExpBufferStr(query,
   11544             :                              "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
   11545             :                              "opc.opcname AS opcname, "
   11546             :                              "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
   11547             :                              "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
   11548             :                              "opc.opcdefault, "
   11549             :                              "CASE WHEN rngcollation = st.typcollation THEN 0 "
   11550             :                              "     ELSE rngcollation END AS collation, "
   11551             :                              "rngcanonical, rngsubdiff "
   11552             :                              "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
   11553             :                              "     pg_catalog.pg_opclass opc "
   11554             :                              "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
   11555             :                              "rngtypid = $1");
   11556             : 
   11557          84 :         ExecuteSqlStatement(fout, query->data);
   11558             : 
   11559          84 :         fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
   11560             :     }
   11561             : 
   11562         232 :     printfPQExpBuffer(query,
   11563             :                       "EXECUTE dumpRangeType('%u')",
   11564             :                       tyinfo->dobj.catId.oid);
   11565             : 
   11566         232 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11567             : 
   11568         232 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11569         232 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11570             : 
   11571             :     /*
   11572             :      * CASCADE shouldn't be required here as for normal types since the I/O
   11573             :      * functions are generic and do not get dropped.
   11574             :      */
   11575         232 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11576             : 
   11577         232 :     if (dopt->binary_upgrade)
   11578          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11579             :                                                  tyinfo->dobj.catId.oid,
   11580             :                                                  false, true);
   11581             : 
   11582         232 :     appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
   11583             :                       qualtypname);
   11584             : 
   11585         232 :     appendPQExpBuffer(q, "\n    subtype = %s",
   11586             :                       PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
   11587             : 
   11588         232 :     if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
   11589         232 :         appendPQExpBuffer(q, ",\n    multirange_type_name = %s",
   11590             :                           PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
   11591             : 
   11592             :     /* print subtype_opclass only if not default for subtype */
   11593         232 :     if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
   11594             :     {
   11595          68 :         char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
   11596          68 :         char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
   11597             : 
   11598          68 :         appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
   11599             :                           fmtId(nspname));
   11600          68 :         appendPQExpBufferStr(q, fmtId(opcname));
   11601             :     }
   11602             : 
   11603         232 :     collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
   11604         232 :     if (OidIsValid(collationOid))
   11605             :     {
   11606          78 :         CollInfo   *coll = findCollationByOid(collationOid);
   11607             : 
   11608          78 :         if (coll)
   11609          78 :             appendPQExpBuffer(q, ",\n    collation = %s",
   11610          78 :                               fmtQualifiedDumpable(coll));
   11611             :     }
   11612             : 
   11613         232 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
   11614         232 :     if (strcmp(procname, "-") != 0)
   11615          18 :         appendPQExpBuffer(q, ",\n    canonical = %s", procname);
   11616             : 
   11617         232 :     procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
   11618         232 :     if (strcmp(procname, "-") != 0)
   11619          46 :         appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
   11620             : 
   11621         232 :     appendPQExpBufferStr(q, "\n);\n");
   11622             : 
   11623         232 :     if (dopt->binary_upgrade)
   11624          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11625             :                                         "TYPE", qtypname,
   11626          16 :                                         tyinfo->dobj.namespace->dobj.name);
   11627             : 
   11628         232 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11629         232 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11630         232 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11631             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11632             :                                   .owner = tyinfo->rolname,
   11633             :                                   .description = "TYPE",
   11634             :                                   .section = SECTION_PRE_DATA,
   11635             :                                   .createStmt = q->data,
   11636             :                                   .dropStmt = delq->data));
   11637             : 
   11638             :     /* Dump Type Comments and Security Labels */
   11639         232 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11640         104 :         dumpComment(fout, "TYPE", qtypname,
   11641         104 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11642             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11643             : 
   11644         232 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11645           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11646           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11647             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11648             : 
   11649         232 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11650          68 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11651             :                 qtypname, NULL,
   11652          68 :                 tyinfo->dobj.namespace->dobj.name,
   11653             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11654             : 
   11655         232 :     PQclear(res);
   11656         232 :     destroyPQExpBuffer(q);
   11657         232 :     destroyPQExpBuffer(delq);
   11658         232 :     destroyPQExpBuffer(query);
   11659         232 :     free(qtypname);
   11660         232 :     free(qualtypname);
   11661         232 : }
   11662             : 
   11663             : /*
   11664             :  * dumpUndefinedType
   11665             :  *    writes out to fout the queries to recreate a !typisdefined type
   11666             :  *
   11667             :  * This is a shell type, but we use different terminology to distinguish
   11668             :  * this case from where we have to emit a shell type definition to break
   11669             :  * circular dependencies.  An undefined type shouldn't ever have anything
   11670             :  * depending on it.
   11671             :  */
   11672             : static void
   11673          78 : dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
   11674             : {
   11675          78 :     DumpOptions *dopt = fout->dopt;
   11676          78 :     PQExpBuffer q = createPQExpBuffer();
   11677          78 :     PQExpBuffer delq = createPQExpBuffer();
   11678             :     char       *qtypname;
   11679             :     char       *qualtypname;
   11680             : 
   11681          78 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11682          78 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11683             : 
   11684          78 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   11685             : 
   11686          78 :     if (dopt->binary_upgrade)
   11687           4 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11688             :                                                  tyinfo->dobj.catId.oid,
   11689             :                                                  false, false);
   11690             : 
   11691          78 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   11692             :                       qualtypname);
   11693             : 
   11694          78 :     if (dopt->binary_upgrade)
   11695           4 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11696             :                                         "TYPE", qtypname,
   11697           4 :                                         tyinfo->dobj.namespace->dobj.name);
   11698             : 
   11699          78 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11700          78 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11701          78 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11702             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11703             :                                   .owner = tyinfo->rolname,
   11704             :                                   .description = "TYPE",
   11705             :                                   .section = SECTION_PRE_DATA,
   11706             :                                   .createStmt = q->data,
   11707             :                                   .dropStmt = delq->data));
   11708             : 
   11709             :     /* Dump Type Comments and Security Labels */
   11710          78 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11711          68 :         dumpComment(fout, "TYPE", qtypname,
   11712          68 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11713             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11714             : 
   11715          78 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11716           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11717           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11718             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11719             : 
   11720          78 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11721           0 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11722             :                 qtypname, NULL,
   11723           0 :                 tyinfo->dobj.namespace->dobj.name,
   11724             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11725             : 
   11726          78 :     destroyPQExpBuffer(q);
   11727          78 :     destroyPQExpBuffer(delq);
   11728          78 :     free(qtypname);
   11729          78 :     free(qualtypname);
   11730          78 : }
   11731             : 
   11732             : /*
   11733             :  * dumpBaseType
   11734             :  *    writes out to fout the queries to recreate a user-defined base type
   11735             :  */
   11736             : static void
   11737         558 : dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
   11738             : {
   11739         558 :     DumpOptions *dopt = fout->dopt;
   11740         558 :     PQExpBuffer q = createPQExpBuffer();
   11741         558 :     PQExpBuffer delq = createPQExpBuffer();
   11742         558 :     PQExpBuffer query = createPQExpBuffer();
   11743             :     PGresult   *res;
   11744             :     char       *qtypname;
   11745             :     char       *qualtypname;
   11746             :     char       *typlen;
   11747             :     char       *typinput;
   11748             :     char       *typoutput;
   11749             :     char       *typreceive;
   11750             :     char       *typsend;
   11751             :     char       *typmodin;
   11752             :     char       *typmodout;
   11753             :     char       *typanalyze;
   11754             :     char       *typsubscript;
   11755             :     Oid         typreceiveoid;
   11756             :     Oid         typsendoid;
   11757             :     Oid         typmodinoid;
   11758             :     Oid         typmodoutoid;
   11759             :     Oid         typanalyzeoid;
   11760             :     Oid         typsubscriptoid;
   11761             :     char       *typcategory;
   11762             :     char       *typispreferred;
   11763             :     char       *typdelim;
   11764             :     char       *typbyval;
   11765             :     char       *typalign;
   11766             :     char       *typstorage;
   11767             :     char       *typcollatable;
   11768             :     char       *typdefault;
   11769         558 :     bool        typdefault_is_literal = false;
   11770             : 
   11771         558 :     if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
   11772             :     {
   11773             :         /* Set up query for type-specific details */
   11774          84 :         appendPQExpBufferStr(query,
   11775             :                              "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
   11776             :                              "SELECT typlen, "
   11777             :                              "typinput, typoutput, typreceive, typsend, "
   11778             :                              "typreceive::pg_catalog.oid AS typreceiveoid, "
   11779             :                              "typsend::pg_catalog.oid AS typsendoid, "
   11780             :                              "typanalyze, "
   11781             :                              "typanalyze::pg_catalog.oid AS typanalyzeoid, "
   11782             :                              "typdelim, typbyval, typalign, typstorage, "
   11783             :                              "typmodin, typmodout, "
   11784             :                              "typmodin::pg_catalog.oid AS typmodinoid, "
   11785             :                              "typmodout::pg_catalog.oid AS typmodoutoid, "
   11786             :                              "typcategory, typispreferred, "
   11787             :                              "(typcollation <> 0) AS typcollatable, "
   11788             :                              "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
   11789             : 
   11790          84 :         if (fout->remoteVersion >= 140000)
   11791          84 :             appendPQExpBufferStr(query,
   11792             :                                  "typsubscript, "
   11793             :                                  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
   11794             :         else
   11795           0 :             appendPQExpBufferStr(query,
   11796             :                                  "'-' AS typsubscript, 0 AS typsubscriptoid ");
   11797             : 
   11798          84 :         appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
   11799             :                              "WHERE oid = $1");
   11800             : 
   11801          84 :         ExecuteSqlStatement(fout, query->data);
   11802             : 
   11803          84 :         fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
   11804             :     }
   11805             : 
   11806         558 :     printfPQExpBuffer(query,
   11807             :                       "EXECUTE dumpBaseType('%u')",
   11808             :                       tyinfo->dobj.catId.oid);
   11809             : 
   11810         558 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   11811             : 
   11812         558 :     typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
   11813         558 :     typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
   11814         558 :     typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
   11815         558 :     typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
   11816         558 :     typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
   11817         558 :     typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
   11818         558 :     typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
   11819         558 :     typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
   11820         558 :     typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
   11821         558 :     typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
   11822         558 :     typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
   11823         558 :     typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
   11824         558 :     typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
   11825         558 :     typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
   11826         558 :     typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
   11827         558 :     typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
   11828         558 :     typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
   11829         558 :     typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
   11830         558 :     typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
   11831         558 :     typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
   11832         558 :     typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
   11833         558 :     typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
   11834         558 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   11835           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   11836         558 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   11837             :     {
   11838          88 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   11839          88 :         typdefault_is_literal = true;   /* it needs quotes */
   11840             :     }
   11841             :     else
   11842         470 :         typdefault = NULL;
   11843             : 
   11844         558 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   11845         558 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   11846             : 
   11847             :     /*
   11848             :      * The reason we include CASCADE is that the circular dependency between
   11849             :      * the type and its I/O functions makes it impossible to drop the type any
   11850             :      * other way.
   11851             :      */
   11852         558 :     appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
   11853             : 
   11854             :     /*
   11855             :      * We might already have a shell type, but setting pg_type_oid is
   11856             :      * harmless, and in any case we'd better set the array type OID.
   11857             :      */
   11858         558 :     if (dopt->binary_upgrade)
   11859          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   11860             :                                                  tyinfo->dobj.catId.oid,
   11861             :                                                  false, false);
   11862             : 
   11863         558 :     appendPQExpBuffer(q,
   11864             :                       "CREATE TYPE %s (\n"
   11865             :                       "    INTERNALLENGTH = %s",
   11866             :                       qualtypname,
   11867         558 :                       (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
   11868             : 
   11869             :     /* regproc result is sufficiently quoted already */
   11870         558 :     appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
   11871         558 :     appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
   11872         558 :     if (OidIsValid(typreceiveoid))
   11873         408 :         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
   11874         558 :     if (OidIsValid(typsendoid))
   11875         408 :         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
   11876         558 :     if (OidIsValid(typmodinoid))
   11877          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
   11878         558 :     if (OidIsValid(typmodoutoid))
   11879          70 :         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
   11880         558 :     if (OidIsValid(typanalyzeoid))
   11881           6 :         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
   11882             : 
   11883         558 :     if (strcmp(typcollatable, "t") == 0)
   11884          60 :         appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
   11885             : 
   11886         558 :     if (typdefault != NULL)
   11887             :     {
   11888          88 :         appendPQExpBufferStr(q, ",\n    DEFAULT = ");
   11889          88 :         if (typdefault_is_literal)
   11890          88 :             appendStringLiteralAH(q, typdefault, fout);
   11891             :         else
   11892           0 :             appendPQExpBufferStr(q, typdefault);
   11893             :     }
   11894             : 
   11895         558 :     if (OidIsValid(typsubscriptoid))
   11896          58 :         appendPQExpBuffer(q, ",\n    SUBSCRIPT = %s", typsubscript);
   11897             : 
   11898         558 :     if (OidIsValid(tyinfo->typelem))
   11899          52 :         appendPQExpBuffer(q, ",\n    ELEMENT = %s",
   11900             :                           getFormattedTypeName(fout, tyinfo->typelem,
   11901             :                                                zeroIsError));
   11902             : 
   11903         558 :     if (strcmp(typcategory, "U") != 0)
   11904             :     {
   11905         310 :         appendPQExpBufferStr(q, ",\n    CATEGORY = ");
   11906         310 :         appendStringLiteralAH(q, typcategory, fout);
   11907             :     }
   11908             : 
   11909         558 :     if (strcmp(typispreferred, "t") == 0)
   11910          58 :         appendPQExpBufferStr(q, ",\n    PREFERRED = true");
   11911             : 
   11912         558 :     if (typdelim && strcmp(typdelim, ",") != 0)
   11913             :     {
   11914           6 :         appendPQExpBufferStr(q, ",\n    DELIMITER = ");
   11915           6 :         appendStringLiteralAH(q, typdelim, fout);
   11916             :     }
   11917             : 
   11918         558 :     if (*typalign == TYPALIGN_CHAR)
   11919          24 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
   11920         534 :     else if (*typalign == TYPALIGN_SHORT)
   11921          12 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
   11922         522 :     else if (*typalign == TYPALIGN_INT)
   11923         372 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
   11924         150 :     else if (*typalign == TYPALIGN_DOUBLE)
   11925         150 :         appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
   11926             : 
   11927         558 :     if (*typstorage == TYPSTORAGE_PLAIN)
   11928         408 :         appendPQExpBufferStr(q, ",\n    STORAGE = plain");
   11929         150 :     else if (*typstorage == TYPSTORAGE_EXTERNAL)
   11930           0 :         appendPQExpBufferStr(q, ",\n    STORAGE = external");
   11931         150 :     else if (*typstorage == TYPSTORAGE_EXTENDED)
   11932         132 :         appendPQExpBufferStr(q, ",\n    STORAGE = extended");
   11933          18 :     else if (*typstorage == TYPSTORAGE_MAIN)
   11934          18 :         appendPQExpBufferStr(q, ",\n    STORAGE = main");
   11935             : 
   11936         558 :     if (strcmp(typbyval, "t") == 0)
   11937         266 :         appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
   11938             : 
   11939         558 :     appendPQExpBufferStr(q, "\n);\n");
   11940             : 
   11941         558 :     if (dopt->binary_upgrade)
   11942          16 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   11943             :                                         "TYPE", qtypname,
   11944          16 :                                         tyinfo->dobj.namespace->dobj.name);
   11945             : 
   11946         558 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   11947         558 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   11948         558 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   11949             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   11950             :                                   .owner = tyinfo->rolname,
   11951             :                                   .description = "TYPE",
   11952             :                                   .section = SECTION_PRE_DATA,
   11953             :                                   .createStmt = q->data,
   11954             :                                   .dropStmt = delq->data));
   11955             : 
   11956             :     /* Dump Type Comments and Security Labels */
   11957         558 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   11958         488 :         dumpComment(fout, "TYPE", qtypname,
   11959         488 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11960             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11961             : 
   11962         558 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   11963           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   11964           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   11965             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   11966             : 
   11967         558 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   11968          68 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   11969             :                 qtypname, NULL,
   11970          68 :                 tyinfo->dobj.namespace->dobj.name,
   11971             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   11972             : 
   11973         558 :     PQclear(res);
   11974         558 :     destroyPQExpBuffer(q);
   11975         558 :     destroyPQExpBuffer(delq);
   11976         558 :     destroyPQExpBuffer(query);
   11977         558 :     free(qtypname);
   11978         558 :     free(qualtypname);
   11979         558 : }
   11980             : 
   11981             : /*
   11982             :  * dumpDomain
   11983             :  *    writes out to fout the queries to recreate a user-defined domain
   11984             :  */
   11985             : static void
   11986         278 : dumpDomain(Archive *fout, const TypeInfo *tyinfo)
   11987             : {
   11988         278 :     DumpOptions *dopt = fout->dopt;
   11989         278 :     PQExpBuffer q = createPQExpBuffer();
   11990         278 :     PQExpBuffer delq = createPQExpBuffer();
   11991         278 :     PQExpBuffer query = createPQExpBuffer();
   11992             :     PGresult   *res;
   11993             :     int         i;
   11994             :     char       *qtypname;
   11995             :     char       *qualtypname;
   11996             :     char       *typnotnull;
   11997             :     char       *typdefn;
   11998             :     char       *typdefault;
   11999             :     Oid         typcollation;
   12000         278 :     bool        typdefault_is_literal = false;
   12001             : 
   12002         278 :     if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
   12003             :     {
   12004             :         /* Set up query for domain-specific details */
   12005          78 :         appendPQExpBufferStr(query,
   12006             :                              "PREPARE dumpDomain(pg_catalog.oid) AS\n");
   12007             : 
   12008          78 :         appendPQExpBufferStr(query, "SELECT t.typnotnull, "
   12009             :                              "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
   12010             :                              "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
   12011             :                              "t.typdefault, "
   12012             :                              "CASE WHEN t.typcollation <> u.typcollation "
   12013             :                              "THEN t.typcollation ELSE 0 END AS typcollation "
   12014             :                              "FROM pg_catalog.pg_type t "
   12015             :                              "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
   12016             :                              "WHERE t.oid = $1");
   12017             : 
   12018          78 :         ExecuteSqlStatement(fout, query->data);
   12019             : 
   12020          78 :         fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
   12021             :     }
   12022             : 
   12023         278 :     printfPQExpBuffer(query,
   12024             :                       "EXECUTE dumpDomain('%u')",
   12025             :                       tyinfo->dobj.catId.oid);
   12026             : 
   12027         278 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12028             : 
   12029         278 :     typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
   12030         278 :     typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
   12031         278 :     if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
   12032          78 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
   12033         200 :     else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
   12034             :     {
   12035           0 :         typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
   12036           0 :         typdefault_is_literal = true;   /* it needs quotes */
   12037             :     }
   12038             :     else
   12039         200 :         typdefault = NULL;
   12040         278 :     typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
   12041             : 
   12042         278 :     if (dopt->binary_upgrade)
   12043          44 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12044             :                                                  tyinfo->dobj.catId.oid,
   12045             :                                                  true,  /* force array type */
   12046             :                                                  false);    /* force multirange type */
   12047             : 
   12048         278 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12049         278 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12050             : 
   12051         278 :     appendPQExpBuffer(q,
   12052             :                       "CREATE DOMAIN %s AS %s",
   12053             :                       qualtypname,
   12054             :                       typdefn);
   12055             : 
   12056             :     /* Print collation only if different from base type's collation */
   12057         278 :     if (OidIsValid(typcollation))
   12058             :     {
   12059             :         CollInfo   *coll;
   12060             : 
   12061          68 :         coll = findCollationByOid(typcollation);
   12062          68 :         if (coll)
   12063          68 :             appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
   12064             :     }
   12065             : 
   12066         278 :     if (typnotnull[0] == 't')
   12067          30 :         appendPQExpBufferStr(q, " NOT NULL");
   12068             : 
   12069         278 :     if (typdefault != NULL)
   12070             :     {
   12071          78 :         appendPQExpBufferStr(q, " DEFAULT ");
   12072          78 :         if (typdefault_is_literal)
   12073           0 :             appendStringLiteralAH(q, typdefault, fout);
   12074             :         else
   12075          78 :             appendPQExpBufferStr(q, typdefault);
   12076             :     }
   12077             : 
   12078         278 :     PQclear(res);
   12079             : 
   12080             :     /*
   12081             :      * Add any CHECK constraints for the domain
   12082             :      */
   12083         466 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12084             :     {
   12085         188 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12086             : 
   12087         188 :         if (!domcheck->separate)
   12088         188 :             appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
   12089         188 :                               fmtId(domcheck->dobj.name), domcheck->condef);
   12090             :     }
   12091             : 
   12092         278 :     appendPQExpBufferStr(q, ";\n");
   12093             : 
   12094         278 :     appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
   12095             : 
   12096         278 :     if (dopt->binary_upgrade)
   12097          44 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12098             :                                         "DOMAIN", qtypname,
   12099          44 :                                         tyinfo->dobj.namespace->dobj.name);
   12100             : 
   12101         278 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12102         278 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12103         278 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12104             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12105             :                                   .owner = tyinfo->rolname,
   12106             :                                   .description = "DOMAIN",
   12107             :                                   .section = SECTION_PRE_DATA,
   12108             :                                   .createStmt = q->data,
   12109             :                                   .dropStmt = delq->data));
   12110             : 
   12111             :     /* Dump Domain Comments and Security Labels */
   12112         278 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12113           0 :         dumpComment(fout, "DOMAIN", qtypname,
   12114           0 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12115             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12116             : 
   12117         278 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12118           0 :         dumpSecLabel(fout, "DOMAIN", qtypname,
   12119           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12120             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12121             : 
   12122         278 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12123          68 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12124             :                 qtypname, NULL,
   12125          68 :                 tyinfo->dobj.namespace->dobj.name,
   12126             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12127             : 
   12128             :     /* Dump any per-constraint comments */
   12129         466 :     for (i = 0; i < tyinfo->nDomChecks; i++)
   12130             :     {
   12131         188 :         ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
   12132         188 :         PQExpBuffer conprefix = createPQExpBuffer();
   12133             : 
   12134         188 :         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
   12135         188 :                           fmtId(domcheck->dobj.name));
   12136             : 
   12137         188 :         if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
   12138          68 :             dumpComment(fout, conprefix->data, qtypname,
   12139          68 :                         tyinfo->dobj.namespace->dobj.name,
   12140             :                         tyinfo->rolname,
   12141             :                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
   12142             : 
   12143         188 :         destroyPQExpBuffer(conprefix);
   12144             :     }
   12145             : 
   12146         278 :     destroyPQExpBuffer(q);
   12147         278 :     destroyPQExpBuffer(delq);
   12148         278 :     destroyPQExpBuffer(query);
   12149         278 :     free(qtypname);
   12150         278 :     free(qualtypname);
   12151         278 : }
   12152             : 
   12153             : /*
   12154             :  * dumpCompositeType
   12155             :  *    writes out to fout the queries to recreate a user-defined stand-alone
   12156             :  *    composite type
   12157             :  */
   12158             : static void
   12159         264 : dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
   12160             : {
   12161         264 :     DumpOptions *dopt = fout->dopt;
   12162         264 :     PQExpBuffer q = createPQExpBuffer();
   12163         264 :     PQExpBuffer dropped = createPQExpBuffer();
   12164         264 :     PQExpBuffer delq = createPQExpBuffer();
   12165         264 :     PQExpBuffer query = createPQExpBuffer();
   12166             :     PGresult   *res;
   12167             :     char       *qtypname;
   12168             :     char       *qualtypname;
   12169             :     int         ntups;
   12170             :     int         i_attname;
   12171             :     int         i_atttypdefn;
   12172             :     int         i_attlen;
   12173             :     int         i_attalign;
   12174             :     int         i_attisdropped;
   12175             :     int         i_attcollation;
   12176             :     int         i;
   12177             :     int         actual_atts;
   12178             : 
   12179         264 :     if (!fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE])
   12180             :     {
   12181             :         /*
   12182             :          * Set up query for type-specific details.
   12183             :          *
   12184             :          * Since we only want to dump COLLATE clauses for attributes whose
   12185             :          * collation is different from their type's default, we use a CASE
   12186             :          * here to suppress uninteresting attcollations cheaply.  atttypid
   12187             :          * will be 0 for dropped columns; collation does not matter for those.
   12188             :          */
   12189         114 :         appendPQExpBufferStr(query,
   12190             :                              "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
   12191             :                              "SELECT a.attname, a.attnum, "
   12192             :                              "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
   12193             :                              "a.attlen, a.attalign, a.attisdropped, "
   12194             :                              "CASE WHEN a.attcollation <> at.typcollation "
   12195             :                              "THEN a.attcollation ELSE 0 END AS attcollation "
   12196             :                              "FROM pg_catalog.pg_type ct "
   12197             :                              "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
   12198             :                              "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
   12199             :                              "WHERE ct.oid = $1 "
   12200             :                              "ORDER BY a.attnum");
   12201             : 
   12202         114 :         ExecuteSqlStatement(fout, query->data);
   12203             : 
   12204         114 :         fout->is_prepared[PREPQUERY_DUMPCOMPOSITETYPE] = true;
   12205             :     }
   12206             : 
   12207         264 :     printfPQExpBuffer(query,
   12208             :                       "EXECUTE dumpCompositeType('%u')",
   12209             :                       tyinfo->dobj.catId.oid);
   12210             : 
   12211         264 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   12212             : 
   12213         264 :     ntups = PQntuples(res);
   12214             : 
   12215         264 :     i_attname = PQfnumber(res, "attname");
   12216         264 :     i_atttypdefn = PQfnumber(res, "atttypdefn");
   12217         264 :     i_attlen = PQfnumber(res, "attlen");
   12218         264 :     i_attalign = PQfnumber(res, "attalign");
   12219         264 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12220         264 :     i_attcollation = PQfnumber(res, "attcollation");
   12221             : 
   12222         264 :     if (dopt->binary_upgrade)
   12223             :     {
   12224          36 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12225             :                                                  tyinfo->dobj.catId.oid,
   12226             :                                                  false, false);
   12227          36 :         binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
   12228             :     }
   12229             : 
   12230         264 :     qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
   12231         264 :     qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
   12232             : 
   12233         264 :     appendPQExpBuffer(q, "CREATE TYPE %s AS (",
   12234             :                       qualtypname);
   12235             : 
   12236         264 :     actual_atts = 0;
   12237         836 :     for (i = 0; i < ntups; i++)
   12238             :     {
   12239             :         char       *attname;
   12240             :         char       *atttypdefn;
   12241             :         char       *attlen;
   12242             :         char       *attalign;
   12243             :         bool        attisdropped;
   12244             :         Oid         attcollation;
   12245             : 
   12246         572 :         attname = PQgetvalue(res, i, i_attname);
   12247         572 :         atttypdefn = PQgetvalue(res, i, i_atttypdefn);
   12248         572 :         attlen = PQgetvalue(res, i, i_attlen);
   12249         572 :         attalign = PQgetvalue(res, i, i_attalign);
   12250         572 :         attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
   12251         572 :         attcollation = atooid(PQgetvalue(res, i, i_attcollation));
   12252             : 
   12253         572 :         if (attisdropped && !dopt->binary_upgrade)
   12254          16 :             continue;
   12255             : 
   12256             :         /* Format properly if not first attr */
   12257         556 :         if (actual_atts++ > 0)
   12258         292 :             appendPQExpBufferChar(q, ',');
   12259         556 :         appendPQExpBufferStr(q, "\n\t");
   12260             : 
   12261         556 :         if (!attisdropped)
   12262             :         {
   12263         552 :             appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
   12264             : 
   12265             :             /* Add collation if not default for the column type */
   12266         552 :             if (OidIsValid(attcollation))
   12267             :             {
   12268             :                 CollInfo   *coll;
   12269             : 
   12270           0 :                 coll = findCollationByOid(attcollation);
   12271           0 :                 if (coll)
   12272           0 :                     appendPQExpBuffer(q, " COLLATE %s",
   12273           0 :                                       fmtQualifiedDumpable(coll));
   12274             :             }
   12275             :         }
   12276             :         else
   12277             :         {
   12278             :             /*
   12279             :              * This is a dropped attribute and we're in binary_upgrade mode.
   12280             :              * Insert a placeholder for it in the CREATE TYPE command, and set
   12281             :              * length and alignment with direct UPDATE to the catalogs
   12282             :              * afterwards. See similar code in dumpTableSchema().
   12283             :              */
   12284           4 :             appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
   12285             : 
   12286             :             /* stash separately for insertion after the CREATE TYPE */
   12287           4 :             appendPQExpBufferStr(dropped,
   12288             :                                  "\n-- For binary upgrade, recreate dropped column.\n");
   12289           4 :             appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
   12290             :                               "SET attlen = %s, "
   12291             :                               "attalign = '%s', attbyval = false\n"
   12292             :                               "WHERE attname = ", attlen, attalign);
   12293           4 :             appendStringLiteralAH(dropped, attname, fout);
   12294           4 :             appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
   12295           4 :             appendStringLiteralAH(dropped, qualtypname, fout);
   12296           4 :             appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
   12297             : 
   12298           4 :             appendPQExpBuffer(dropped, "ALTER TYPE %s ",
   12299             :                               qualtypname);
   12300           4 :             appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
   12301             :                               fmtId(attname));
   12302             :         }
   12303             :     }
   12304         264 :     appendPQExpBufferStr(q, "\n);\n");
   12305         264 :     appendPQExpBufferStr(q, dropped->data);
   12306             : 
   12307         264 :     appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
   12308             : 
   12309         264 :     if (dopt->binary_upgrade)
   12310          36 :         binary_upgrade_extension_member(q, &tyinfo->dobj,
   12311             :                                         "TYPE", qtypname,
   12312          36 :                                         tyinfo->dobj.namespace->dobj.name);
   12313             : 
   12314         264 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12315         230 :         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
   12316         230 :                      ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
   12317             :                                   .namespace = tyinfo->dobj.namespace->dobj.name,
   12318             :                                   .owner = tyinfo->rolname,
   12319             :                                   .description = "TYPE",
   12320             :                                   .section = SECTION_PRE_DATA,
   12321             :                                   .createStmt = q->data,
   12322             :                                   .dropStmt = delq->data));
   12323             : 
   12324             : 
   12325             :     /* Dump Type Comments and Security Labels */
   12326         264 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12327          68 :         dumpComment(fout, "TYPE", qtypname,
   12328          68 :                     tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12329             :                     tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12330             : 
   12331         264 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12332           0 :         dumpSecLabel(fout, "TYPE", qtypname,
   12333           0 :                      tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
   12334             :                      tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
   12335             : 
   12336         264 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
   12337          36 :         dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
   12338             :                 qtypname, NULL,
   12339          36 :                 tyinfo->dobj.namespace->dobj.name,
   12340             :                 NULL, tyinfo->rolname, &tyinfo->dacl);
   12341             : 
   12342             :     /* Dump any per-column comments */
   12343         264 :     if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   12344          68 :         dumpCompositeTypeColComments(fout, tyinfo, res);
   12345             : 
   12346         264 :     PQclear(res);
   12347         264 :     destroyPQExpBuffer(q);
   12348         264 :     destroyPQExpBuffer(dropped);
   12349         264 :     destroyPQExpBuffer(delq);
   12350         264 :     destroyPQExpBuffer(query);
   12351         264 :     free(qtypname);
   12352         264 :     free(qualtypname);
   12353         264 : }
   12354             : 
   12355             : /*
   12356             :  * dumpCompositeTypeColComments
   12357             :  *    writes out to fout the queries to recreate comments on the columns of
   12358             :  *    a user-defined stand-alone composite type.
   12359             :  *
   12360             :  * The caller has already made a query to collect the names and attnums
   12361             :  * of the type's columns, so we just pass that result into here rather
   12362             :  * than reading them again.
   12363             :  */
   12364             : static void
   12365          68 : dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
   12366             :                              PGresult *res)
   12367             : {
   12368             :     CommentItem *comments;
   12369             :     int         ncomments;
   12370             :     PQExpBuffer query;
   12371             :     PQExpBuffer target;
   12372             :     int         i;
   12373             :     int         ntups;
   12374             :     int         i_attname;
   12375             :     int         i_attnum;
   12376             :     int         i_attisdropped;
   12377             : 
   12378             :     /* do nothing, if --no-comments is supplied */
   12379          68 :     if (fout->dopt->no_comments)
   12380           0 :         return;
   12381             : 
   12382             :     /* Search for comments associated with type's pg_class OID */
   12383          68 :     ncomments = findComments(RelationRelationId, tyinfo->typrelid,
   12384             :                              &comments);
   12385             : 
   12386             :     /* If no comments exist, we're done */
   12387          68 :     if (ncomments <= 0)
   12388           0 :         return;
   12389             : 
   12390             :     /* Build COMMENT ON statements */
   12391          68 :     query = createPQExpBuffer();
   12392          68 :     target = createPQExpBuffer();
   12393             : 
   12394          68 :     ntups = PQntuples(res);
   12395          68 :     i_attnum = PQfnumber(res, "attnum");
   12396          68 :     i_attname = PQfnumber(res, "attname");
   12397          68 :     i_attisdropped = PQfnumber(res, "attisdropped");
   12398         136 :     while (ncomments > 0)
   12399             :     {
   12400             :         const char *attname;
   12401             : 
   12402          68 :         attname = NULL;
   12403          68 :         for (i = 0; i < ntups; i++)
   12404             :         {
   12405          68 :             if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
   12406          68 :                 PQgetvalue(res, i, i_attisdropped)[0] != 't')
   12407             :             {
   12408          68 :                 attname = PQgetvalue(res, i, i_attname);
   12409          68 :                 break;
   12410             :             }
   12411             :         }
   12412          68 :         if (attname)            /* just in case we don't find it */
   12413             :         {
   12414          68 :             const char *descr = comments->descr;
   12415             : 
   12416          68 :             resetPQExpBuffer(target);
   12417          68 :             appendPQExpBuffer(target, "COLUMN %s.",
   12418          68 :                               fmtId(tyinfo->dobj.name));
   12419          68 :             appendPQExpBufferStr(target, fmtId(attname));
   12420             : 
   12421          68 :             resetPQExpBuffer(query);
   12422          68 :             appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
   12423          68 :                               fmtQualifiedDumpable(tyinfo));
   12424          68 :             appendPQExpBuffer(query, "%s IS ", fmtId(attname));
   12425          68 :             appendStringLiteralAH(query, descr, fout);
   12426          68 :             appendPQExpBufferStr(query, ";\n");
   12427             : 
   12428          68 :             ArchiveEntry(fout, nilCatalogId, createDumpId(),
   12429          68 :                          ARCHIVE_OPTS(.tag = target->data,
   12430             :                                       .namespace = tyinfo->dobj.namespace->dobj.name,
   12431             :                                       .owner = tyinfo->rolname,
   12432             :                                       .description = "COMMENT",
   12433             :                                       .section = SECTION_NONE,
   12434             :                                       .createStmt = query->data,
   12435             :                                       .deps = &(tyinfo->dobj.dumpId),
   12436             :                                       .nDeps = 1));
   12437             :         }
   12438             : 
   12439          68 :         comments++;
   12440          68 :         ncomments--;
   12441             :     }
   12442             : 
   12443          68 :     destroyPQExpBuffer(query);
   12444          68 :     destroyPQExpBuffer(target);
   12445             : }
   12446             : 
   12447             : /*
   12448             :  * dumpShellType
   12449             :  *    writes out to fout the queries to create a shell type
   12450             :  *
   12451             :  * We dump a shell definition in advance of the I/O functions for the type.
   12452             :  */
   12453             : static void
   12454         150 : dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
   12455             : {
   12456         150 :     DumpOptions *dopt = fout->dopt;
   12457             :     PQExpBuffer q;
   12458             : 
   12459             :     /* Do nothing if not dumping schema */
   12460         150 :     if (!dopt->dumpSchema)
   12461          12 :         return;
   12462             : 
   12463         138 :     q = createPQExpBuffer();
   12464             : 
   12465             :     /*
   12466             :      * Note the lack of a DROP command for the shell type; any required DROP
   12467             :      * is driven off the base type entry, instead.  This interacts with
   12468             :      * _printTocEntry()'s use of the presence of a DROP command to decide
   12469             :      * whether an entry needs an ALTER OWNER command.  We don't want to alter
   12470             :      * the shell type's owner immediately on creation; that should happen only
   12471             :      * after it's filled in, otherwise the backend complains.
   12472             :      */
   12473             : 
   12474         138 :     if (dopt->binary_upgrade)
   12475          16 :         binary_upgrade_set_type_oids_by_type_oid(fout, q,
   12476          16 :                                                  stinfo->baseType->dobj.catId.oid,
   12477             :                                                  false, false);
   12478             : 
   12479         138 :     appendPQExpBuffer(q, "CREATE TYPE %s;\n",
   12480         138 :                       fmtQualifiedDumpable(stinfo));
   12481             : 
   12482         138 :     if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12483         138 :         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
   12484         138 :                      ARCHIVE_OPTS(.tag = stinfo->dobj.name,
   12485             :                                   .namespace = stinfo->dobj.namespace->dobj.name,
   12486             :                                   .owner = stinfo->baseType->rolname,
   12487             :                                   .description = "SHELL TYPE",
   12488             :                                   .section = SECTION_PRE_DATA,
   12489             :                                   .createStmt = q->data));
   12490             : 
   12491         138 :     destroyPQExpBuffer(q);
   12492             : }
   12493             : 
   12494             : /*
   12495             :  * dumpProcLang
   12496             :  *        writes out to fout the queries to recreate a user-defined
   12497             :  *        procedural language
   12498             :  */
   12499             : static void
   12500         172 : dumpProcLang(Archive *fout, const ProcLangInfo *plang)
   12501             : {
   12502         172 :     DumpOptions *dopt = fout->dopt;
   12503             :     PQExpBuffer defqry;
   12504             :     PQExpBuffer delqry;
   12505             :     bool        useParams;
   12506             :     char       *qlanname;
   12507             :     FuncInfo   *funcInfo;
   12508         172 :     FuncInfo   *inlineInfo = NULL;
   12509         172 :     FuncInfo   *validatorInfo = NULL;
   12510             : 
   12511             :     /* Do nothing if not dumping schema */
   12512         172 :     if (!dopt->dumpSchema)
   12513          26 :         return;
   12514             : 
   12515             :     /*
   12516             :      * Try to find the support function(s).  It is not an error if we don't
   12517             :      * find them --- if the functions are in the pg_catalog schema, as is
   12518             :      * standard in 8.1 and up, then we won't have loaded them. (In this case
   12519             :      * we will emit a parameterless CREATE LANGUAGE command, which will
   12520             :      * require PL template knowledge in the backend to reload.)
   12521             :      */
   12522             : 
   12523         146 :     funcInfo = findFuncByOid(plang->lanplcallfoid);
   12524         146 :     if (funcInfo != NULL && !funcInfo->dobj.dump)
   12525           4 :         funcInfo = NULL;        /* treat not-dumped same as not-found */
   12526             : 
   12527         146 :     if (OidIsValid(plang->laninline))
   12528             :     {
   12529          80 :         inlineInfo = findFuncByOid(plang->laninline);
   12530          80 :         if (inlineInfo != NULL && !inlineInfo->dobj.dump)
   12531           2 :             inlineInfo = NULL;
   12532             :     }
   12533             : 
   12534         146 :     if (OidIsValid(plang->lanvalidator))
   12535             :     {
   12536          80 :         validatorInfo = findFuncByOid(plang->lanvalidator);
   12537          80 :         if (validatorInfo != NULL && !validatorInfo->dobj.dump)
   12538           2 :             validatorInfo = NULL;
   12539             :     }
   12540             : 
   12541             :     /*
   12542             :      * If the functions are dumpable then emit a complete CREATE LANGUAGE with
   12543             :      * parameters.  Otherwise, we'll write a parameterless command, which will
   12544             :      * be interpreted as CREATE EXTENSION.
   12545             :      */
   12546          64 :     useParams = (funcInfo != NULL &&
   12547         274 :                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
   12548          64 :                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
   12549             : 
   12550         146 :     defqry = createPQExpBuffer();
   12551         146 :     delqry = createPQExpBuffer();
   12552             : 
   12553         146 :     qlanname = pg_strdup(fmtId(plang->dobj.name));
   12554             : 
   12555         146 :     appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
   12556             :                       qlanname);
   12557             : 
   12558         146 :     if (useParams)
   12559             :     {
   12560          64 :         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
   12561          64 :                           plang->lanpltrusted ? "TRUSTED " : "",
   12562             :                           qlanname);
   12563          64 :         appendPQExpBuffer(defqry, " HANDLER %s",
   12564          64 :                           fmtQualifiedDumpable(funcInfo));
   12565          64 :         if (OidIsValid(plang->laninline))
   12566           0 :             appendPQExpBuffer(defqry, " INLINE %s",
   12567           0 :                               fmtQualifiedDumpable(inlineInfo));
   12568          64 :         if (OidIsValid(plang->lanvalidator))
   12569           0 :             appendPQExpBuffer(defqry, " VALIDATOR %s",
   12570           0 :                               fmtQualifiedDumpable(validatorInfo));
   12571             :     }
   12572             :     else
   12573             :     {
   12574             :         /*
   12575             :          * If not dumping parameters, then use CREATE OR REPLACE so that the
   12576             :          * command will not fail if the language is preinstalled in the target
   12577             :          * database.
   12578             :          *
   12579             :          * Modern servers will interpret this as CREATE EXTENSION IF NOT
   12580             :          * EXISTS; perhaps we should emit that instead?  But it might just add
   12581             :          * confusion.
   12582             :          */
   12583          82 :         appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
   12584             :                           qlanname);
   12585             :     }
   12586         146 :     appendPQExpBufferStr(defqry, ";\n");
   12587             : 
   12588         146 :     if (dopt->binary_upgrade)
   12589           4 :         binary_upgrade_extension_member(defqry, &plang->dobj,
   12590             :                                         "LANGUAGE", qlanname, NULL);
   12591             : 
   12592         146 :     if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
   12593          66 :         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
   12594          66 :                      ARCHIVE_OPTS(.tag = plang->dobj.name,
   12595             :                                   .owner = plang->lanowner,
   12596             :                                   .description = "PROCEDURAL LANGUAGE",
   12597             :                                   .section = SECTION_PRE_DATA,
   12598             :                                   .createStmt = defqry->data,
   12599             :                                   .dropStmt = delqry->data,
   12600             :                                   ));
   12601             : 
   12602             :     /* Dump Proc Lang Comments and Security Labels */
   12603         146 :     if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
   12604           0 :         dumpComment(fout, "LANGUAGE", qlanname,
   12605             :                     NULL, plang->lanowner,
   12606             :                     plang->dobj.catId, 0, plang->dobj.dumpId);
   12607             : 
   12608         146 :     if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
   12609           0 :         dumpSecLabel(fout, "LANGUAGE", qlanname,
   12610             :                      NULL, plang->lanowner,
   12611             :                      plang->dobj.catId, 0, plang->dobj.dumpId);
   12612             : 
   12613         146 :     if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
   12614          80 :         dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
   12615             :                 qlanname, NULL, NULL,
   12616             :                 NULL, plang->lanowner, &plang->dacl);
   12617             : 
   12618         146 :     free(qlanname);
   12619             : 
   12620         146 :     destroyPQExpBuffer(defqry);
   12621         146 :     destroyPQExpBuffer(delqry);
   12622             : }
   12623             : 
   12624             : /*
   12625             :  * format_function_arguments: generate function name and argument list
   12626             :  *
   12627             :  * This is used when we can rely on pg_get_function_arguments to format
   12628             :  * the argument list.  Note, however, that pg_get_function_arguments
   12629             :  * does not special-case zero-argument aggregates.
   12630             :  */
   12631             : static char *
   12632        8292 : format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
   12633             : {
   12634             :     PQExpBufferData fn;
   12635             : 
   12636        8292 :     initPQExpBuffer(&fn);
   12637        8292 :     appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
   12638        8292 :     if (is_agg && finfo->nargs == 0)
   12639         160 :         appendPQExpBufferStr(&fn, "(*)");
   12640             :     else
   12641        8132 :         appendPQExpBuffer(&fn, "(%s)", funcargs);
   12642        8292 :     return fn.data;
   12643             : }
   12644             : 
   12645             : /*
   12646             :  * format_function_signature: generate function name and argument list
   12647             :  *
   12648             :  * Only a minimal list of input argument types is generated; this is
   12649             :  * sufficient to reference the function, but not to define it.
   12650             :  *
   12651             :  * If honor_quotes is false then the function name is never quoted.
   12652             :  * This is appropriate for use in TOC tags, but not in SQL commands.
   12653             :  */
   12654             : static char *
   12655        4374 : format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
   12656             : {
   12657             :     PQExpBufferData fn;
   12658             :     int         j;
   12659             : 
   12660        4374 :     initPQExpBuffer(&fn);
   12661        4374 :     if (honor_quotes)
   12662         802 :         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
   12663             :     else
   12664        3572 :         appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
   12665        7998 :     for (j = 0; j < finfo->nargs; j++)
   12666             :     {
   12667        3624 :         if (j > 0)
   12668         844 :             appendPQExpBufferStr(&fn, ", ");
   12669             : 
   12670        3624 :         appendPQExpBufferStr(&fn,
   12671        3624 :                              getFormattedTypeName(fout, finfo->argtypes[j],
   12672             :                                                   zeroIsError));
   12673             :     }
   12674        4374 :     appendPQExpBufferChar(&fn, ')');
   12675        4374 :     return fn.data;
   12676             : }
   12677             : 
   12678             : 
   12679             : /*
   12680             :  * dumpFunc:
   12681             :  *    dump out one function
   12682             :  */
   12683             : static void
   12684        3696 : dumpFunc(Archive *fout, const FuncInfo *finfo)
   12685             : {
   12686        3696 :     DumpOptions *dopt = fout->dopt;
   12687             :     PQExpBuffer query;
   12688             :     PQExpBuffer q;
   12689             :     PQExpBuffer delqry;
   12690             :     PQExpBuffer asPart;
   12691             :     PGresult   *res;
   12692             :     char       *funcsig;        /* identity signature */
   12693        3696 :     char       *funcfullsig = NULL; /* full signature */
   12694             :     char       *funcsig_tag;
   12695             :     char       *qual_funcsig;
   12696             :     char       *proretset;
   12697             :     char       *prosrc;
   12698             :     char       *probin;
   12699             :     char       *prosqlbody;
   12700             :     char       *funcargs;
   12701             :     char       *funciargs;
   12702             :     char       *funcresult;
   12703             :     char       *protrftypes;
   12704             :     char       *prokind;
   12705             :     char       *provolatile;
   12706             :     char       *proisstrict;
   12707             :     char       *prosecdef;
   12708             :     char       *proleakproof;
   12709             :     char       *proconfig;
   12710             :     char       *procost;
   12711             :     char       *prorows;
   12712             :     char       *prosupport;
   12713             :     char       *proparallel;
   12714             :     char       *lanname;
   12715        3696 :     char      **configitems = NULL;
   12716        3696 :     int         nconfigitems = 0;
   12717             :     const char *keyword;
   12718             : 
   12719             :     /* Do nothing if not dumping schema */
   12720        3696 :     if (!dopt->dumpSchema)
   12721         124 :         return;
   12722             : 
   12723        3572 :     query = createPQExpBuffer();
   12724        3572 :     q = createPQExpBuffer();
   12725        3572 :     delqry = createPQExpBuffer();
   12726        3572 :     asPart = createPQExpBuffer();
   12727             : 
   12728        3572 :     if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
   12729             :     {
   12730             :         /* Set up query for function-specific details */
   12731         126 :         appendPQExpBufferStr(query,
   12732             :                              "PREPARE dumpFunc(pg_catalog.oid) AS\n");
   12733             : 
   12734         126 :         appendPQExpBufferStr(query,
   12735             :                              "SELECT\n"
   12736             :                              "proretset,\n"
   12737             :                              "prosrc,\n"
   12738             :                              "probin,\n"
   12739             :                              "provolatile,\n"
   12740             :                              "proisstrict,\n"
   12741             :                              "prosecdef,\n"
   12742             :                              "lanname,\n"
   12743             :                              "proconfig,\n"
   12744             :                              "procost,\n"
   12745             :                              "prorows,\n"
   12746             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   12747             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
   12748             :                              "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
   12749             :                              "proleakproof,\n");
   12750             : 
   12751         126 :         if (fout->remoteVersion >= 90500)
   12752         126 :             appendPQExpBufferStr(query,
   12753             :                                  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
   12754             :         else
   12755           0 :             appendPQExpBufferStr(query,
   12756             :                                  "NULL AS protrftypes,\n");
   12757             : 
   12758         126 :         if (fout->remoteVersion >= 90600)
   12759         126 :             appendPQExpBufferStr(query,
   12760             :                                  "proparallel,\n");
   12761             :         else
   12762           0 :             appendPQExpBufferStr(query,
   12763             :                                  "'u' AS proparallel,\n");
   12764             : 
   12765         126 :         if (fout->remoteVersion >= 110000)
   12766         126 :             appendPQExpBufferStr(query,
   12767             :                                  "prokind,\n");
   12768             :         else
   12769           0 :             appendPQExpBufferStr(query,
   12770             :                                  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
   12771             : 
   12772         126 :         if (fout->remoteVersion >= 120000)
   12773         126 :             appendPQExpBufferStr(query,
   12774             :                                  "prosupport,\n");
   12775             :         else
   12776           0 :             appendPQExpBufferStr(query,
   12777             :                                  "'-' AS prosupport,\n");
   12778             : 
   12779         126 :         if (fout->remoteVersion >= 140000)
   12780         126 :             appendPQExpBufferStr(query,
   12781             :                                  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
   12782             :         else
   12783           0 :             appendPQExpBufferStr(query,
   12784             :                                  "NULL AS prosqlbody\n");
   12785             : 
   12786         126 :         appendPQExpBufferStr(query,
   12787             :                              "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
   12788             :                              "WHERE p.oid = $1 "
   12789             :                              "AND l.oid = p.prolang");
   12790             : 
   12791         126 :         ExecuteSqlStatement(fout, query->data);
   12792             : 
   12793         126 :         fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
   12794             :     }
   12795             : 
   12796        3572 :     printfPQExpBuffer(query,
   12797             :                       "EXECUTE dumpFunc('%u')",
   12798             :                       finfo->dobj.catId.oid);
   12799             : 
   12800        3572 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   12801             : 
   12802        3572 :     proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
   12803        3572 :     if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
   12804             :     {
   12805        3472 :         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
   12806        3472 :         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
   12807        3472 :         prosqlbody = NULL;
   12808             :     }
   12809             :     else
   12810             :     {
   12811         100 :         prosrc = NULL;
   12812         100 :         probin = NULL;
   12813         100 :         prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
   12814             :     }
   12815        3572 :     funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   12816        3572 :     funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   12817        3572 :     funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
   12818        3572 :     protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
   12819        3572 :     prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
   12820        3572 :     provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
   12821        3572 :     proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
   12822        3572 :     prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
   12823        3572 :     proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
   12824        3572 :     proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
   12825        3572 :     procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
   12826        3572 :     prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
   12827        3572 :     prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
   12828        3572 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   12829        3572 :     lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
   12830             : 
   12831             :     /*
   12832             :      * See backend/commands/functioncmds.c for details of how the 'AS' clause
   12833             :      * is used.
   12834             :      */
   12835        3572 :     if (prosqlbody)
   12836             :     {
   12837         100 :         appendPQExpBufferStr(asPart, prosqlbody);
   12838             :     }
   12839        3472 :     else if (probin[0] != '\0')
   12840             :     {
   12841         298 :         appendPQExpBufferStr(asPart, "AS ");
   12842         298 :         appendStringLiteralAH(asPart, probin, fout);
   12843         298 :         if (prosrc[0] != '\0')
   12844             :         {
   12845         298 :             appendPQExpBufferStr(asPart, ", ");
   12846             : 
   12847             :             /*
   12848             :              * where we have bin, use dollar quoting if allowed and src
   12849             :              * contains quote or backslash; else use regular quoting.
   12850             :              */
   12851         298 :             if (dopt->disable_dollar_quoting ||
   12852         298 :                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
   12853         298 :                 appendStringLiteralAH(asPart, prosrc, fout);
   12854             :             else
   12855           0 :                 appendStringLiteralDQ(asPart, prosrc, NULL);
   12856             :         }
   12857             :     }
   12858             :     else
   12859             :     {
   12860        3174 :         appendPQExpBufferStr(asPart, "AS ");
   12861             :         /* with no bin, dollar quote src unconditionally if allowed */
   12862        3174 :         if (dopt->disable_dollar_quoting)
   12863           0 :             appendStringLiteralAH(asPart, prosrc, fout);
   12864             :         else
   12865        3174 :             appendStringLiteralDQ(asPart, prosrc, NULL);
   12866             :     }
   12867             : 
   12868        3572 :     if (*proconfig)
   12869             :     {
   12870          30 :         if (!parsePGArray(proconfig, &configitems, &nconfigitems))
   12871           0 :             pg_fatal("could not parse %s array", "proconfig");
   12872             :     }
   12873             :     else
   12874             :     {
   12875        3542 :         configitems = NULL;
   12876        3542 :         nconfigitems = 0;
   12877             :     }
   12878             : 
   12879        3572 :     funcfullsig = format_function_arguments(finfo, funcargs, false);
   12880        3572 :     funcsig = format_function_arguments(finfo, funciargs, false);
   12881             : 
   12882        3572 :     funcsig_tag = format_function_signature(fout, finfo, false);
   12883             : 
   12884        3572 :     qual_funcsig = psprintf("%s.%s",
   12885        3572 :                             fmtId(finfo->dobj.namespace->dobj.name),
   12886             :                             funcsig);
   12887             : 
   12888        3572 :     if (prokind[0] == PROKIND_PROCEDURE)
   12889         188 :         keyword = "PROCEDURE";
   12890             :     else
   12891        3384 :         keyword = "FUNCTION"; /* works for window functions too */
   12892             : 
   12893        3572 :     appendPQExpBuffer(delqry, "DROP %s %s;\n",
   12894             :                       keyword, qual_funcsig);
   12895             : 
   12896        7144 :     appendPQExpBuffer(q, "CREATE %s %s.%s",
   12897             :                       keyword,
   12898        3572 :                       fmtId(finfo->dobj.namespace->dobj.name),
   12899             :                       funcfullsig ? funcfullsig :
   12900             :                       funcsig);
   12901             : 
   12902        3572 :     if (prokind[0] == PROKIND_PROCEDURE)
   12903             :          /* no result type to output */ ;
   12904        3384 :     else if (funcresult)
   12905        3384 :         appendPQExpBuffer(q, " RETURNS %s", funcresult);
   12906             :     else
   12907           0 :         appendPQExpBuffer(q, " RETURNS %s%s",
   12908           0 :                           (proretset[0] == 't') ? "SETOF " : "",
   12909             :                           getFormattedTypeName(fout, finfo->prorettype,
   12910             :                                                zeroIsError));
   12911             : 
   12912        3572 :     appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
   12913             : 
   12914        3572 :     if (*protrftypes)
   12915             :     {
   12916           0 :         Oid        *typeids = pg_malloc(FUNC_MAX_ARGS * sizeof(Oid));
   12917             :         int         i;
   12918             : 
   12919           0 :         appendPQExpBufferStr(q, " TRANSFORM ");
   12920           0 :         parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
   12921           0 :         for (i = 0; typeids[i]; i++)
   12922             :         {
   12923           0 :             if (i != 0)
   12924           0 :                 appendPQExpBufferStr(q, ", ");
   12925           0 :             appendPQExpBuffer(q, "FOR TYPE %s",
   12926           0 :                               getFormattedTypeName(fout, typeids[i], zeroAsNone));
   12927             :         }
   12928             : 
   12929           0 :         free(typeids);
   12930             :     }
   12931             : 
   12932        3572 :     if (prokind[0] == PROKIND_WINDOW)
   12933          10 :         appendPQExpBufferStr(q, " WINDOW");
   12934             : 
   12935        3572 :     if (provolatile[0] != PROVOLATILE_VOLATILE)
   12936             :     {
   12937         710 :         if (provolatile[0] == PROVOLATILE_IMMUTABLE)
   12938         668 :             appendPQExpBufferStr(q, " IMMUTABLE");
   12939          42 :         else if (provolatile[0] == PROVOLATILE_STABLE)
   12940          42 :             appendPQExpBufferStr(q, " STABLE");
   12941           0 :         else if (provolatile[0] != PROVOLATILE_VOLATILE)
   12942           0 :             pg_fatal("unrecognized provolatile value for function \"%s\"",
   12943             :                      finfo->dobj.name);
   12944             :     }
   12945             : 
   12946        3572 :     if (proisstrict[0] == 't')
   12947         718 :         appendPQExpBufferStr(q, " STRICT");
   12948             : 
   12949        3572 :     if (prosecdef[0] == 't')
   12950           0 :         appendPQExpBufferStr(q, " SECURITY DEFINER");
   12951             : 
   12952        3572 :     if (proleakproof[0] == 't')
   12953          20 :         appendPQExpBufferStr(q, " LEAKPROOF");
   12954             : 
   12955             :     /*
   12956             :      * COST and ROWS are emitted only if present and not default, so as not to
   12957             :      * break backwards-compatibility of the dump without need.  Keep this code
   12958             :      * in sync with the defaults in functioncmds.c.
   12959             :      */
   12960        3572 :     if (strcmp(procost, "0") != 0)
   12961             :     {
   12962        3572 :         if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
   12963             :         {
   12964             :             /* default cost is 1 */
   12965         772 :             if (strcmp(procost, "1") != 0)
   12966           0 :                 appendPQExpBuffer(q, " COST %s", procost);
   12967             :         }
   12968             :         else
   12969             :         {
   12970             :             /* default cost is 100 */
   12971        2800 :             if (strcmp(procost, "100") != 0)
   12972          12 :                 appendPQExpBuffer(q, " COST %s", procost);
   12973             :         }
   12974             :     }
   12975        3572 :     if (proretset[0] == 't' &&
   12976         378 :         strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
   12977           0 :         appendPQExpBuffer(q, " ROWS %s", prorows);
   12978             : 
   12979        3572 :     if (strcmp(prosupport, "-") != 0)
   12980             :     {
   12981             :         /* We rely on regprocout to provide quoting and qualification */
   12982          88 :         appendPQExpBuffer(q, " SUPPORT %s", prosupport);
   12983             :     }
   12984             : 
   12985        3572 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   12986             :     {
   12987         240 :         if (proparallel[0] == PROPARALLEL_SAFE)
   12988         230 :             appendPQExpBufferStr(q, " PARALLEL SAFE");
   12989          10 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   12990          10 :             appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
   12991           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   12992           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   12993             :                      finfo->dobj.name);
   12994             :     }
   12995             : 
   12996        3642 :     for (int i = 0; i < nconfigitems; i++)
   12997             :     {
   12998             :         /* we feel free to scribble on configitems[] here */
   12999          70 :         char       *configitem = configitems[i];
   13000             :         char       *pos;
   13001             : 
   13002          70 :         pos = strchr(configitem, '=');
   13003          70 :         if (pos == NULL)
   13004           0 :             continue;
   13005          70 :         *pos++ = '\0';
   13006          70 :         appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
   13007             : 
   13008             :         /*
   13009             :          * Variables that are marked GUC_LIST_QUOTE were already fully quoted
   13010             :          * by flatten_set_variable_args() before they were put into the
   13011             :          * proconfig array.  However, because the quoting rules used there
   13012             :          * aren't exactly like SQL's, we have to break the list value apart
   13013             :          * and then quote the elements as string literals.  (The elements may
   13014             :          * be double-quoted as-is, but we can't just feed them to the SQL
   13015             :          * parser; it would do the wrong thing with elements that are
   13016             :          * zero-length or longer than NAMEDATALEN.)
   13017             :          *
   13018             :          * Variables that are not so marked should just be emitted as simple
   13019             :          * string literals.  If the variable is not known to
   13020             :          * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
   13021             :          * to use GUC_LIST_QUOTE for extension variables.
   13022             :          */
   13023          70 :         if (variable_is_guc_list_quote(configitem))
   13024             :         {
   13025             :             char      **namelist;
   13026             :             char      **nameptr;
   13027             : 
   13028             :             /* Parse string into list of identifiers */
   13029             :             /* this shouldn't fail really */
   13030          20 :             if (SplitGUCList(pos, ',', &namelist))
   13031             :             {
   13032          70 :                 for (nameptr = namelist; *nameptr; nameptr++)
   13033             :                 {
   13034          50 :                     if (nameptr != namelist)
   13035          30 :                         appendPQExpBufferStr(q, ", ");
   13036          50 :                     appendStringLiteralAH(q, *nameptr, fout);
   13037             :                 }
   13038             :             }
   13039          20 :             pg_free(namelist);
   13040             :         }
   13041             :         else
   13042          50 :             appendStringLiteralAH(q, pos, fout);
   13043             :     }
   13044             : 
   13045        3572 :     appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
   13046             : 
   13047        3572 :     append_depends_on_extension(fout, q, &finfo->dobj,
   13048             :                                 "pg_catalog.pg_proc", keyword,
   13049             :                                 qual_funcsig);
   13050             : 
   13051        3572 :     if (dopt->binary_upgrade)
   13052         582 :         binary_upgrade_extension_member(q, &finfo->dobj,
   13053             :                                         keyword, funcsig,
   13054         582 :                                         finfo->dobj.namespace->dobj.name);
   13055             : 
   13056        3572 :     if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13057        3372 :         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
   13058        3372 :                      ARCHIVE_OPTS(.tag = funcsig_tag,
   13059             :                                   .namespace = finfo->dobj.namespace->dobj.name,
   13060             :                                   .owner = finfo->rolname,
   13061             :                                   .description = keyword,
   13062             :                                   .section = finfo->postponed_def ?
   13063             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   13064             :                                   .createStmt = q->data,
   13065             :                                   .dropStmt = delqry->data));
   13066             : 
   13067             :     /* Dump Function Comments and Security Labels */
   13068        3572 :     if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13069          18 :         dumpComment(fout, keyword, funcsig,
   13070          18 :                     finfo->dobj.namespace->dobj.name, finfo->rolname,
   13071             :                     finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13072             : 
   13073        3572 :     if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   13074           0 :         dumpSecLabel(fout, keyword, funcsig,
   13075           0 :                      finfo->dobj.namespace->dobj.name, finfo->rolname,
   13076             :                      finfo->dobj.catId, 0, finfo->dobj.dumpId);
   13077             : 
   13078        3572 :     if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
   13079         208 :         dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
   13080             :                 funcsig, NULL,
   13081         208 :                 finfo->dobj.namespace->dobj.name,
   13082             :                 NULL, finfo->rolname, &finfo->dacl);
   13083             : 
   13084        3572 :     PQclear(res);
   13085             : 
   13086        3572 :     destroyPQExpBuffer(query);
   13087        3572 :     destroyPQExpBuffer(q);
   13088        3572 :     destroyPQExpBuffer(delqry);
   13089        3572 :     destroyPQExpBuffer(asPart);
   13090        3572 :     free(funcsig);
   13091        3572 :     free(funcfullsig);
   13092        3572 :     free(funcsig_tag);
   13093        3572 :     free(qual_funcsig);
   13094        3572 :     free(configitems);
   13095             : }
   13096             : 
   13097             : 
   13098             : /*
   13099             :  * Dump a user-defined cast
   13100             :  */
   13101             : static void
   13102         138 : dumpCast(Archive *fout, const CastInfo *cast)
   13103             : {
   13104         138 :     DumpOptions *dopt = fout->dopt;
   13105             :     PQExpBuffer defqry;
   13106             :     PQExpBuffer delqry;
   13107             :     PQExpBuffer labelq;
   13108             :     PQExpBuffer castargs;
   13109         138 :     FuncInfo   *funcInfo = NULL;
   13110             :     const char *sourceType;
   13111             :     const char *targetType;
   13112             : 
   13113             :     /* Do nothing if not dumping schema */
   13114         138 :     if (!dopt->dumpSchema)
   13115          12 :         return;
   13116             : 
   13117             :     /* Cannot dump if we don't have the cast function's info */
   13118         126 :     if (OidIsValid(cast->castfunc))
   13119             :     {
   13120          76 :         funcInfo = findFuncByOid(cast->castfunc);
   13121          76 :         if (funcInfo == NULL)
   13122           0 :             pg_fatal("could not find function definition for function with OID %u",
   13123             :                      cast->castfunc);
   13124             :     }
   13125             : 
   13126         126 :     defqry = createPQExpBuffer();
   13127         126 :     delqry = createPQExpBuffer();
   13128         126 :     labelq = createPQExpBuffer();
   13129         126 :     castargs = createPQExpBuffer();
   13130             : 
   13131         126 :     sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
   13132         126 :     targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
   13133         126 :     appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
   13134             :                       sourceType, targetType);
   13135             : 
   13136         126 :     appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
   13137             :                       sourceType, targetType);
   13138             : 
   13139         126 :     switch (cast->castmethod)
   13140             :     {
   13141          50 :         case COERCION_METHOD_BINARY:
   13142          50 :             appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
   13143          50 :             break;
   13144           0 :         case COERCION_METHOD_INOUT:
   13145           0 :             appendPQExpBufferStr(defqry, "WITH INOUT");
   13146           0 :             break;
   13147          76 :         case COERCION_METHOD_FUNCTION:
   13148          76 :             if (funcInfo)
   13149             :             {
   13150          76 :                 char       *fsig = format_function_signature(fout, funcInfo, true);
   13151             : 
   13152             :                 /*
   13153             :                  * Always qualify the function name (format_function_signature
   13154             :                  * won't qualify it).
   13155             :                  */
   13156          76 :                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
   13157          76 :                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
   13158          76 :                 free(fsig);
   13159             :             }
   13160             :             else
   13161           0 :                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
   13162          76 :             break;
   13163           0 :         default:
   13164           0 :             pg_log_warning("bogus value in pg_cast.castmethod field");
   13165             :     }
   13166             : 
   13167         126 :     if (cast->castcontext == 'a')
   13168          66 :         appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
   13169          60 :     else if (cast->castcontext == 'i')
   13170          20 :         appendPQExpBufferStr(defqry, " AS IMPLICIT");
   13171         126 :     appendPQExpBufferStr(defqry, ";\n");
   13172             : 
   13173         126 :     appendPQExpBuffer(labelq, "CAST (%s AS %s)",
   13174             :                       sourceType, targetType);
   13175             : 
   13176         126 :     appendPQExpBuffer(castargs, "(%s AS %s)",
   13177             :                       sourceType, targetType);
   13178             : 
   13179         126 :     if (dopt->binary_upgrade)
   13180          14 :         binary_upgrade_extension_member(defqry, &cast->dobj,
   13181          14 :                                         "CAST", castargs->data, NULL);
   13182             : 
   13183         126 :     if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13184         126 :         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
   13185         126 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13186             :                                   .description = "CAST",
   13187             :                                   .section = SECTION_PRE_DATA,
   13188             :                                   .createStmt = defqry->data,
   13189             :                                   .dropStmt = delqry->data));
   13190             : 
   13191             :     /* Dump Cast Comments */
   13192         126 :     if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
   13193           0 :         dumpComment(fout, "CAST", castargs->data,
   13194             :                     NULL, "",
   13195             :                     cast->dobj.catId, 0, cast->dobj.dumpId);
   13196             : 
   13197         126 :     destroyPQExpBuffer(defqry);
   13198         126 :     destroyPQExpBuffer(delqry);
   13199         126 :     destroyPQExpBuffer(labelq);
   13200         126 :     destroyPQExpBuffer(castargs);
   13201             : }
   13202             : 
   13203             : /*
   13204             :  * Dump a transform
   13205             :  */
   13206             : static void
   13207          88 : dumpTransform(Archive *fout, const TransformInfo *transform)
   13208             : {
   13209          88 :     DumpOptions *dopt = fout->dopt;
   13210             :     PQExpBuffer defqry;
   13211             :     PQExpBuffer delqry;
   13212             :     PQExpBuffer labelq;
   13213             :     PQExpBuffer transformargs;
   13214          88 :     FuncInfo   *fromsqlFuncInfo = NULL;
   13215          88 :     FuncInfo   *tosqlFuncInfo = NULL;
   13216             :     char       *lanname;
   13217             :     const char *transformType;
   13218             : 
   13219             :     /* Do nothing if not dumping schema */
   13220          88 :     if (!dopt->dumpSchema)
   13221          12 :         return;
   13222             : 
   13223             :     /* Cannot dump if we don't have the transform functions' info */
   13224          76 :     if (OidIsValid(transform->trffromsql))
   13225             :     {
   13226          76 :         fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
   13227          76 :         if (fromsqlFuncInfo == NULL)
   13228           0 :             pg_fatal("could not find function definition for function with OID %u",
   13229             :                      transform->trffromsql);
   13230             :     }
   13231          76 :     if (OidIsValid(transform->trftosql))
   13232             :     {
   13233          76 :         tosqlFuncInfo = findFuncByOid(transform->trftosql);
   13234          76 :         if (tosqlFuncInfo == NULL)
   13235           0 :             pg_fatal("could not find function definition for function with OID %u",
   13236             :                      transform->trftosql);
   13237             :     }
   13238             : 
   13239          76 :     defqry = createPQExpBuffer();
   13240          76 :     delqry = createPQExpBuffer();
   13241          76 :     labelq = createPQExpBuffer();
   13242          76 :     transformargs = createPQExpBuffer();
   13243             : 
   13244          76 :     lanname = get_language_name(fout, transform->trflang);
   13245          76 :     transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
   13246             : 
   13247          76 :     appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
   13248             :                       transformType, lanname);
   13249             : 
   13250          76 :     appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
   13251             :                       transformType, lanname);
   13252             : 
   13253          76 :     if (!transform->trffromsql && !transform->trftosql)
   13254           0 :         pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
   13255             : 
   13256          76 :     if (transform->trffromsql)
   13257             :     {
   13258          76 :         if (fromsqlFuncInfo)
   13259             :         {
   13260          76 :             char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
   13261             : 
   13262             :             /*
   13263             :              * Always qualify the function name (format_function_signature
   13264             :              * won't qualify it).
   13265             :              */
   13266          76 :             appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
   13267          76 :                               fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13268          76 :             free(fsig);
   13269             :         }
   13270             :         else
   13271           0 :             pg_log_warning("bogus value in pg_transform.trffromsql field");
   13272             :     }
   13273             : 
   13274          76 :     if (transform->trftosql)
   13275             :     {
   13276          76 :         if (transform->trffromsql)
   13277          76 :             appendPQExpBufferStr(defqry, ", ");
   13278             : 
   13279          76 :         if (tosqlFuncInfo)
   13280             :         {
   13281          76 :             char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
   13282             : 
   13283             :             /*
   13284             :              * Always qualify the function name (format_function_signature
   13285             :              * won't qualify it).
   13286             :              */
   13287          76 :             appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
   13288          76 :                               fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
   13289          76 :             free(fsig);
   13290             :         }
   13291             :         else
   13292           0 :             pg_log_warning("bogus value in pg_transform.trftosql field");
   13293             :     }
   13294             : 
   13295          76 :     appendPQExpBufferStr(defqry, ");\n");
   13296             : 
   13297          76 :     appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
   13298             :                       transformType, lanname);
   13299             : 
   13300          76 :     appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
   13301             :                       transformType, lanname);
   13302             : 
   13303          76 :     if (dopt->binary_upgrade)
   13304           4 :         binary_upgrade_extension_member(defqry, &transform->dobj,
   13305           4 :                                         "TRANSFORM", transformargs->data, NULL);
   13306             : 
   13307          76 :     if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13308          76 :         ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
   13309          76 :                      ARCHIVE_OPTS(.tag = labelq->data,
   13310             :                                   .description = "TRANSFORM",
   13311             :                                   .section = SECTION_PRE_DATA,
   13312             :                                   .createStmt = defqry->data,
   13313             :                                   .dropStmt = delqry->data,
   13314             :                                   .deps = transform->dobj.dependencies,
   13315             :                                   .nDeps = transform->dobj.nDeps));
   13316             : 
   13317             :     /* Dump Transform Comments */
   13318          76 :     if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
   13319           0 :         dumpComment(fout, "TRANSFORM", transformargs->data,
   13320             :                     NULL, "",
   13321             :                     transform->dobj.catId, 0, transform->dobj.dumpId);
   13322             : 
   13323          76 :     free(lanname);
   13324          76 :     destroyPQExpBuffer(defqry);
   13325          76 :     destroyPQExpBuffer(delqry);
   13326          76 :     destroyPQExpBuffer(labelq);
   13327          76 :     destroyPQExpBuffer(transformargs);
   13328             : }
   13329             : 
   13330             : 
   13331             : /*
   13332             :  * dumpOpr
   13333             :  *    write out a single operator definition
   13334             :  */
   13335             : static void
   13336        5012 : dumpOpr(Archive *fout, const OprInfo *oprinfo)
   13337             : {
   13338        5012 :     DumpOptions *dopt = fout->dopt;
   13339             :     PQExpBuffer query;
   13340             :     PQExpBuffer q;
   13341             :     PQExpBuffer delq;
   13342             :     PQExpBuffer oprid;
   13343             :     PQExpBuffer details;
   13344             :     PGresult   *res;
   13345             :     int         i_oprkind;
   13346             :     int         i_oprcode;
   13347             :     int         i_oprleft;
   13348             :     int         i_oprright;
   13349             :     int         i_oprcom;
   13350             :     int         i_oprnegate;
   13351             :     int         i_oprrest;
   13352             :     int         i_oprjoin;
   13353             :     int         i_oprcanmerge;
   13354             :     int         i_oprcanhash;
   13355             :     char       *oprkind;
   13356             :     char       *oprcode;
   13357             :     char       *oprleft;
   13358             :     char       *oprright;
   13359             :     char       *oprcom;
   13360             :     char       *oprnegate;
   13361             :     char       *oprrest;
   13362             :     char       *oprjoin;
   13363             :     char       *oprcanmerge;
   13364             :     char       *oprcanhash;
   13365             :     char       *oprregproc;
   13366             :     char       *oprref;
   13367             : 
   13368             :     /* Do nothing if not dumping schema */
   13369        5012 :     if (!dopt->dumpSchema)
   13370          12 :         return;
   13371             : 
   13372             :     /*
   13373             :      * some operators are invalid because they were the result of user
   13374             :      * defining operators before commutators exist
   13375             :      */
   13376        5000 :     if (!OidIsValid(oprinfo->oprcode))
   13377          28 :         return;
   13378             : 
   13379        4972 :     query = createPQExpBuffer();
   13380        4972 :     q = createPQExpBuffer();
   13381        4972 :     delq = createPQExpBuffer();
   13382        4972 :     oprid = createPQExpBuffer();
   13383        4972 :     details = createPQExpBuffer();
   13384             : 
   13385        4972 :     if (!fout->is_prepared[PREPQUERY_DUMPOPR])
   13386             :     {
   13387             :         /* Set up query for operator-specific details */
   13388          84 :         appendPQExpBufferStr(query,
   13389             :                              "PREPARE dumpOpr(pg_catalog.oid) AS\n"
   13390             :                              "SELECT oprkind, "
   13391             :                              "oprcode::pg_catalog.regprocedure, "
   13392             :                              "oprleft::pg_catalog.regtype, "
   13393             :                              "oprright::pg_catalog.regtype, "
   13394             :                              "oprcom, "
   13395             :                              "oprnegate, "
   13396             :                              "oprrest::pg_catalog.regprocedure, "
   13397             :                              "oprjoin::pg_catalog.regprocedure, "
   13398             :                              "oprcanmerge, oprcanhash "
   13399             :                              "FROM pg_catalog.pg_operator "
   13400             :                              "WHERE oid = $1");
   13401             : 
   13402          84 :         ExecuteSqlStatement(fout, query->data);
   13403             : 
   13404          84 :         fout->is_prepared[PREPQUERY_DUMPOPR] = true;
   13405             :     }
   13406             : 
   13407        4972 :     printfPQExpBuffer(query,
   13408             :                       "EXECUTE dumpOpr('%u')",
   13409             :                       oprinfo->dobj.catId.oid);
   13410             : 
   13411        4972 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13412             : 
   13413        4972 :     i_oprkind = PQfnumber(res, "oprkind");
   13414        4972 :     i_oprcode = PQfnumber(res, "oprcode");
   13415        4972 :     i_oprleft = PQfnumber(res, "oprleft");
   13416        4972 :     i_oprright = PQfnumber(res, "oprright");
   13417        4972 :     i_oprcom = PQfnumber(res, "oprcom");
   13418        4972 :     i_oprnegate = PQfnumber(res, "oprnegate");
   13419        4972 :     i_oprrest = PQfnumber(res, "oprrest");
   13420        4972 :     i_oprjoin = PQfnumber(res, "oprjoin");
   13421        4972 :     i_oprcanmerge = PQfnumber(res, "oprcanmerge");
   13422        4972 :     i_oprcanhash = PQfnumber(res, "oprcanhash");
   13423             : 
   13424        4972 :     oprkind = PQgetvalue(res, 0, i_oprkind);
   13425        4972 :     oprcode = PQgetvalue(res, 0, i_oprcode);
   13426        4972 :     oprleft = PQgetvalue(res, 0, i_oprleft);
   13427        4972 :     oprright = PQgetvalue(res, 0, i_oprright);
   13428        4972 :     oprcom = PQgetvalue(res, 0, i_oprcom);
   13429        4972 :     oprnegate = PQgetvalue(res, 0, i_oprnegate);
   13430        4972 :     oprrest = PQgetvalue(res, 0, i_oprrest);
   13431        4972 :     oprjoin = PQgetvalue(res, 0, i_oprjoin);
   13432        4972 :     oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
   13433        4972 :     oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
   13434             : 
   13435             :     /* In PG14 upwards postfix operator support does not exist anymore. */
   13436        4972 :     if (strcmp(oprkind, "r") == 0)
   13437           0 :         pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
   13438             :                        oprcode);
   13439             : 
   13440        4972 :     oprregproc = convertRegProcReference(oprcode);
   13441        4972 :     if (oprregproc)
   13442             :     {
   13443        4972 :         appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
   13444        4972 :         free(oprregproc);
   13445             :     }
   13446             : 
   13447        4972 :     appendPQExpBuffer(oprid, "%s (",
   13448             :                       oprinfo->dobj.name);
   13449             : 
   13450             :     /*
   13451             :      * right unary means there's a left arg and left unary means there's a
   13452             :      * right arg.  (Although the "r" case is dead code for PG14 and later,
   13453             :      * continue to support it in case we're dumping from an old server.)
   13454             :      */
   13455        4972 :     if (strcmp(oprkind, "r") == 0 ||
   13456        4972 :         strcmp(oprkind, "b") == 0)
   13457             :     {
   13458        4686 :         appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
   13459        4686 :         appendPQExpBufferStr(oprid, oprleft);
   13460             :     }
   13461             :     else
   13462         286 :         appendPQExpBufferStr(oprid, "NONE");
   13463             : 
   13464        4972 :     if (strcmp(oprkind, "l") == 0 ||
   13465        4686 :         strcmp(oprkind, "b") == 0)
   13466             :     {
   13467        4972 :         appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
   13468        4972 :         appendPQExpBuffer(oprid, ", %s)", oprright);
   13469             :     }
   13470             :     else
   13471           0 :         appendPQExpBufferStr(oprid, ", NONE)");
   13472             : 
   13473        4972 :     oprref = getFormattedOperatorName(oprcom);
   13474        4972 :     if (oprref)
   13475             :     {
   13476        3322 :         appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
   13477        3322 :         free(oprref);
   13478             :     }
   13479             : 
   13480        4972 :     oprref = getFormattedOperatorName(oprnegate);
   13481        4972 :     if (oprref)
   13482             :     {
   13483        2326 :         appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
   13484        2326 :         free(oprref);
   13485             :     }
   13486             : 
   13487        4972 :     if (strcmp(oprcanmerge, "t") == 0)
   13488         370 :         appendPQExpBufferStr(details, ",\n    MERGES");
   13489             : 
   13490        4972 :     if (strcmp(oprcanhash, "t") == 0)
   13491         276 :         appendPQExpBufferStr(details, ",\n    HASHES");
   13492             : 
   13493        4972 :     oprregproc = convertRegProcReference(oprrest);
   13494        4972 :     if (oprregproc)
   13495             :     {
   13496        3028 :         appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
   13497        3028 :         free(oprregproc);
   13498             :     }
   13499             : 
   13500        4972 :     oprregproc = convertRegProcReference(oprjoin);
   13501        4972 :     if (oprregproc)
   13502             :     {
   13503        3028 :         appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
   13504        3028 :         free(oprregproc);
   13505             :     }
   13506             : 
   13507        4972 :     appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
   13508        4972 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13509             :                       oprid->data);
   13510             : 
   13511        4972 :     appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
   13512        4972 :                       fmtId(oprinfo->dobj.namespace->dobj.name),
   13513             :                       oprinfo->dobj.name, details->data);
   13514             : 
   13515        4972 :     if (dopt->binary_upgrade)
   13516          24 :         binary_upgrade_extension_member(q, &oprinfo->dobj,
   13517          24 :                                         "OPERATOR", oprid->data,
   13518          24 :                                         oprinfo->dobj.namespace->dobj.name);
   13519             : 
   13520        4972 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13521        4972 :         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
   13522        4972 :                      ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
   13523             :                                   .namespace = oprinfo->dobj.namespace->dobj.name,
   13524             :                                   .owner = oprinfo->rolname,
   13525             :                                   .description = "OPERATOR",
   13526             :                                   .section = SECTION_PRE_DATA,
   13527             :                                   .createStmt = q->data,
   13528             :                                   .dropStmt = delq->data));
   13529             : 
   13530             :     /* Dump Operator Comments */
   13531        4972 :     if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13532        4794 :         dumpComment(fout, "OPERATOR", oprid->data,
   13533        4794 :                     oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
   13534             :                     oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
   13535             : 
   13536        4972 :     PQclear(res);
   13537             : 
   13538        4972 :     destroyPQExpBuffer(query);
   13539        4972 :     destroyPQExpBuffer(q);
   13540        4972 :     destroyPQExpBuffer(delq);
   13541        4972 :     destroyPQExpBuffer(oprid);
   13542        4972 :     destroyPQExpBuffer(details);
   13543             : }
   13544             : 
   13545             : /*
   13546             :  * Convert a function reference obtained from pg_operator
   13547             :  *
   13548             :  * Returns allocated string of what to print, or NULL if function references
   13549             :  * is InvalidOid. Returned string is expected to be free'd by the caller.
   13550             :  *
   13551             :  * The input is a REGPROCEDURE display; we have to strip the argument-types
   13552             :  * part.
   13553             :  */
   13554             : static char *
   13555       14916 : convertRegProcReference(const char *proc)
   13556             : {
   13557             :     char       *name;
   13558             :     char       *paren;
   13559             :     bool        inquote;
   13560             : 
   13561             :     /* In all cases "-" means a null reference */
   13562       14916 :     if (strcmp(proc, "-") == 0)
   13563        3888 :         return NULL;
   13564             : 
   13565       11028 :     name = pg_strdup(proc);
   13566             :     /* find non-double-quoted left paren */
   13567       11028 :     inquote = false;
   13568      132892 :     for (paren = name; *paren; paren++)
   13569             :     {
   13570      132892 :         if (*paren == '(' && !inquote)
   13571             :         {
   13572       11028 :             *paren = '\0';
   13573       11028 :             break;
   13574             :         }
   13575      121864 :         if (*paren == '"')
   13576         100 :             inquote = !inquote;
   13577             :     }
   13578       11028 :     return name;
   13579             : }
   13580             : 
   13581             : /*
   13582             :  * getFormattedOperatorName - retrieve the operator name for the
   13583             :  * given operator OID (presented in string form).
   13584             :  *
   13585             :  * Returns an allocated string, or NULL if the given OID is invalid.
   13586             :  * Caller is responsible for free'ing result string.
   13587             :  *
   13588             :  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
   13589             :  * useful in commands where the operator's argument types can be inferred from
   13590             :  * context.  We always schema-qualify the name, though.  The predecessor to
   13591             :  * this code tried to skip the schema qualification if possible, but that led
   13592             :  * to wrong results in corner cases, such as if an operator and its negator
   13593             :  * are in different schemas.
   13594             :  */
   13595             : static char *
   13596       10518 : getFormattedOperatorName(const char *oproid)
   13597             : {
   13598             :     OprInfo    *oprInfo;
   13599             : 
   13600             :     /* In all cases "0" means a null reference */
   13601       10518 :     if (strcmp(oproid, "0") == 0)
   13602        4870 :         return NULL;
   13603             : 
   13604        5648 :     oprInfo = findOprByOid(atooid(oproid));
   13605        5648 :     if (oprInfo == NULL)
   13606             :     {
   13607           0 :         pg_log_warning("could not find operator with OID %s",
   13608             :                        oproid);
   13609           0 :         return NULL;
   13610             :     }
   13611             : 
   13612        5648 :     return psprintf("OPERATOR(%s.%s)",
   13613        5648 :                     fmtId(oprInfo->dobj.namespace->dobj.name),
   13614             :                     oprInfo->dobj.name);
   13615             : }
   13616             : 
   13617             : /*
   13618             :  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
   13619             :  *
   13620             :  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
   13621             :  * argument lists of these functions are predetermined.  Note that the
   13622             :  * caller should ensure we are in the proper schema, because the results
   13623             :  * are search path dependent!
   13624             :  */
   13625             : static char *
   13626         430 : convertTSFunction(Archive *fout, Oid funcOid)
   13627             : {
   13628             :     char       *result;
   13629             :     char        query[128];
   13630             :     PGresult   *res;
   13631             : 
   13632         430 :     snprintf(query, sizeof(query),
   13633             :              "SELECT '%u'::pg_catalog.regproc", funcOid);
   13634         430 :     res = ExecuteSqlQueryForSingleRow(fout, query);
   13635             : 
   13636         430 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   13637             : 
   13638         430 :     PQclear(res);
   13639             : 
   13640         430 :     return result;
   13641             : }
   13642             : 
   13643             : /*
   13644             :  * dumpAccessMethod
   13645             :  *    write out a single access method definition
   13646             :  */
   13647             : static void
   13648         168 : dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
   13649             : {
   13650         168 :     DumpOptions *dopt = fout->dopt;
   13651             :     PQExpBuffer q;
   13652             :     PQExpBuffer delq;
   13653             :     char       *qamname;
   13654             : 
   13655             :     /* Do nothing if not dumping schema */
   13656         168 :     if (!dopt->dumpSchema)
   13657          24 :         return;
   13658             : 
   13659         144 :     q = createPQExpBuffer();
   13660         144 :     delq = createPQExpBuffer();
   13661             : 
   13662         144 :     qamname = pg_strdup(fmtId(aminfo->dobj.name));
   13663             : 
   13664         144 :     appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
   13665             : 
   13666         144 :     switch (aminfo->amtype)
   13667             :     {
   13668          68 :         case AMTYPE_INDEX:
   13669          68 :             appendPQExpBufferStr(q, "TYPE INDEX ");
   13670          68 :             break;
   13671          76 :         case AMTYPE_TABLE:
   13672          76 :             appendPQExpBufferStr(q, "TYPE TABLE ");
   13673          76 :             break;
   13674           0 :         default:
   13675           0 :             pg_log_warning("invalid type \"%c\" of access method \"%s\"",
   13676             :                            aminfo->amtype, qamname);
   13677           0 :             destroyPQExpBuffer(q);
   13678           0 :             destroyPQExpBuffer(delq);
   13679           0 :             free(qamname);
   13680           0 :             return;
   13681             :     }
   13682             : 
   13683         144 :     appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
   13684             : 
   13685         144 :     appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
   13686             :                       qamname);
   13687             : 
   13688         144 :     if (dopt->binary_upgrade)
   13689           8 :         binary_upgrade_extension_member(q, &aminfo->dobj,
   13690             :                                         "ACCESS METHOD", qamname, NULL);
   13691             : 
   13692         144 :     if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13693         144 :         ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
   13694         144 :                      ARCHIVE_OPTS(.tag = aminfo->dobj.name,
   13695             :                                   .description = "ACCESS METHOD",
   13696             :                                   .section = SECTION_PRE_DATA,
   13697             :                                   .createStmt = q->data,
   13698             :                                   .dropStmt = delq->data));
   13699             : 
   13700             :     /* Dump Access Method Comments */
   13701         144 :     if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13702           0 :         dumpComment(fout, "ACCESS METHOD", qamname,
   13703             :                     NULL, "",
   13704             :                     aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
   13705             : 
   13706         144 :     destroyPQExpBuffer(q);
   13707         144 :     destroyPQExpBuffer(delq);
   13708         144 :     free(qamname);
   13709             : }
   13710             : 
   13711             : /*
   13712             :  * dumpOpclass
   13713             :  *    write out a single operator class definition
   13714             :  */
   13715             : static void
   13716        1332 : dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
   13717             : {
   13718        1332 :     DumpOptions *dopt = fout->dopt;
   13719             :     PQExpBuffer query;
   13720             :     PQExpBuffer q;
   13721             :     PQExpBuffer delq;
   13722             :     PQExpBuffer nameusing;
   13723             :     PGresult   *res;
   13724             :     int         ntups;
   13725             :     int         i_opcintype;
   13726             :     int         i_opckeytype;
   13727             :     int         i_opcdefault;
   13728             :     int         i_opcfamily;
   13729             :     int         i_opcfamilyname;
   13730             :     int         i_opcfamilynsp;
   13731             :     int         i_amname;
   13732             :     int         i_amopstrategy;
   13733             :     int         i_amopopr;
   13734             :     int         i_sortfamily;
   13735             :     int         i_sortfamilynsp;
   13736             :     int         i_amprocnum;
   13737             :     int         i_amproc;
   13738             :     int         i_amproclefttype;
   13739             :     int         i_amprocrighttype;
   13740             :     char       *opcintype;
   13741             :     char       *opckeytype;
   13742             :     char       *opcdefault;
   13743             :     char       *opcfamily;
   13744             :     char       *opcfamilyname;
   13745             :     char       *opcfamilynsp;
   13746             :     char       *amname;
   13747             :     char       *amopstrategy;
   13748             :     char       *amopopr;
   13749             :     char       *sortfamily;
   13750             :     char       *sortfamilynsp;
   13751             :     char       *amprocnum;
   13752             :     char       *amproc;
   13753             :     char       *amproclefttype;
   13754             :     char       *amprocrighttype;
   13755             :     bool        needComma;
   13756             :     int         i;
   13757             : 
   13758             :     /* Do nothing if not dumping schema */
   13759        1332 :     if (!dopt->dumpSchema)
   13760          36 :         return;
   13761             : 
   13762        1296 :     query = createPQExpBuffer();
   13763        1296 :     q = createPQExpBuffer();
   13764        1296 :     delq = createPQExpBuffer();
   13765        1296 :     nameusing = createPQExpBuffer();
   13766             : 
   13767             :     /* Get additional fields from the pg_opclass row */
   13768        1296 :     appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
   13769             :                       "opckeytype::pg_catalog.regtype, "
   13770             :                       "opcdefault, opcfamily, "
   13771             :                       "opfname AS opcfamilyname, "
   13772             :                       "nspname AS opcfamilynsp, "
   13773             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
   13774             :                       "FROM pg_catalog.pg_opclass c "
   13775             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
   13776             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13777             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   13778             :                       opcinfo->dobj.catId.oid);
   13779             : 
   13780        1296 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   13781             : 
   13782        1296 :     i_opcintype = PQfnumber(res, "opcintype");
   13783        1296 :     i_opckeytype = PQfnumber(res, "opckeytype");
   13784        1296 :     i_opcdefault = PQfnumber(res, "opcdefault");
   13785        1296 :     i_opcfamily = PQfnumber(res, "opcfamily");
   13786        1296 :     i_opcfamilyname = PQfnumber(res, "opcfamilyname");
   13787        1296 :     i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
   13788        1296 :     i_amname = PQfnumber(res, "amname");
   13789             : 
   13790             :     /* opcintype may still be needed after we PQclear res */
   13791        1296 :     opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
   13792        1296 :     opckeytype = PQgetvalue(res, 0, i_opckeytype);
   13793        1296 :     opcdefault = PQgetvalue(res, 0, i_opcdefault);
   13794             :     /* opcfamily will still be needed after we PQclear res */
   13795        1296 :     opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
   13796        1296 :     opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
   13797        1296 :     opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
   13798             :     /* amname will still be needed after we PQclear res */
   13799        1296 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   13800             : 
   13801        1296 :     appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
   13802        1296 :                       fmtQualifiedDumpable(opcinfo));
   13803        1296 :     appendPQExpBuffer(delq, " USING %s;\n",
   13804             :                       fmtId(amname));
   13805             : 
   13806             :     /* Build the fixed portion of the CREATE command */
   13807        1296 :     appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
   13808        1296 :                       fmtQualifiedDumpable(opcinfo));
   13809        1296 :     if (strcmp(opcdefault, "t") == 0)
   13810         714 :         appendPQExpBufferStr(q, "DEFAULT ");
   13811        1296 :     appendPQExpBuffer(q, "FOR TYPE %s USING %s",
   13812             :                       opcintype,
   13813             :                       fmtId(amname));
   13814        1296 :     if (strlen(opcfamilyname) > 0)
   13815             :     {
   13816        1296 :         appendPQExpBufferStr(q, " FAMILY ");
   13817        1296 :         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
   13818        1296 :         appendPQExpBufferStr(q, fmtId(opcfamilyname));
   13819             :     }
   13820        1296 :     appendPQExpBufferStr(q, " AS\n    ");
   13821             : 
   13822        1296 :     needComma = false;
   13823             : 
   13824        1296 :     if (strcmp(opckeytype, "-") != 0)
   13825             :     {
   13826         504 :         appendPQExpBuffer(q, "STORAGE %s",
   13827             :                           opckeytype);
   13828         504 :         needComma = true;
   13829             :     }
   13830             : 
   13831        1296 :     PQclear(res);
   13832             : 
   13833             :     /*
   13834             :      * Now fetch and print the OPERATOR entries (pg_amop rows).
   13835             :      *
   13836             :      * Print only those opfamily members that are tied to the opclass by
   13837             :      * pg_depend entries.
   13838             :      */
   13839        1296 :     resetPQExpBuffer(query);
   13840        1296 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   13841             :                       "amopopr::pg_catalog.regoperator, "
   13842             :                       "opfname AS sortfamily, "
   13843             :                       "nspname AS sortfamilynsp "
   13844             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   13845             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   13846             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   13847             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   13848             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   13849             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13850             :                       "AND amopfamily = '%s'::pg_catalog.oid "
   13851             :                       "ORDER BY amopstrategy",
   13852             :                       opcinfo->dobj.catId.oid,
   13853             :                       opcfamily);
   13854             : 
   13855        1296 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13856             : 
   13857        1296 :     ntups = PQntuples(res);
   13858             : 
   13859        1296 :     i_amopstrategy = PQfnumber(res, "amopstrategy");
   13860        1296 :     i_amopopr = PQfnumber(res, "amopopr");
   13861        1296 :     i_sortfamily = PQfnumber(res, "sortfamily");
   13862        1296 :     i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
   13863             : 
   13864        1724 :     for (i = 0; i < ntups; i++)
   13865             :     {
   13866         428 :         amopstrategy = PQgetvalue(res, i, i_amopstrategy);
   13867         428 :         amopopr = PQgetvalue(res, i, i_amopopr);
   13868         428 :         sortfamily = PQgetvalue(res, i, i_sortfamily);
   13869         428 :         sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
   13870             : 
   13871         428 :         if (needComma)
   13872         272 :             appendPQExpBufferStr(q, " ,\n    ");
   13873             : 
   13874         428 :         appendPQExpBuffer(q, "OPERATOR %s %s",
   13875             :                           amopstrategy, amopopr);
   13876             : 
   13877         428 :         if (strlen(sortfamily) > 0)
   13878             :         {
   13879           0 :             appendPQExpBufferStr(q, " FOR ORDER BY ");
   13880           0 :             appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   13881           0 :             appendPQExpBufferStr(q, fmtId(sortfamily));
   13882             :         }
   13883             : 
   13884         428 :         needComma = true;
   13885             :     }
   13886             : 
   13887        1296 :     PQclear(res);
   13888             : 
   13889             :     /*
   13890             :      * Now fetch and print the FUNCTION entries (pg_amproc rows).
   13891             :      *
   13892             :      * Print only those opfamily members that are tied to the opclass by
   13893             :      * pg_depend entries.
   13894             :      *
   13895             :      * We print the amproclefttype/amprocrighttype even though in most cases
   13896             :      * the backend could deduce the right values, because of the corner case
   13897             :      * of a btree sort support function for a cross-type comparison.
   13898             :      */
   13899        1296 :     resetPQExpBuffer(query);
   13900             : 
   13901        1296 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   13902             :                       "amproc::pg_catalog.regprocedure, "
   13903             :                       "amproclefttype::pg_catalog.regtype, "
   13904             :                       "amprocrighttype::pg_catalog.regtype "
   13905             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   13906             :                       "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
   13907             :                       "AND refobjid = '%u'::pg_catalog.oid "
   13908             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   13909             :                       "AND objid = ap.oid "
   13910             :                       "ORDER BY amprocnum",
   13911             :                       opcinfo->dobj.catId.oid);
   13912             : 
   13913        1296 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   13914             : 
   13915        1296 :     ntups = PQntuples(res);
   13916             : 
   13917        1296 :     i_amprocnum = PQfnumber(res, "amprocnum");
   13918        1296 :     i_amproc = PQfnumber(res, "amproc");
   13919        1296 :     i_amproclefttype = PQfnumber(res, "amproclefttype");
   13920        1296 :     i_amprocrighttype = PQfnumber(res, "amprocrighttype");
   13921             : 
   13922        1364 :     for (i = 0; i < ntups; i++)
   13923             :     {
   13924          68 :         amprocnum = PQgetvalue(res, i, i_amprocnum);
   13925          68 :         amproc = PQgetvalue(res, i, i_amproc);
   13926          68 :         amproclefttype = PQgetvalue(res, i, i_amproclefttype);
   13927          68 :         amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
   13928             : 
   13929          68 :         if (needComma)
   13930          68 :             appendPQExpBufferStr(q, " ,\n    ");
   13931             : 
   13932          68 :         appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
   13933             : 
   13934          68 :         if (*amproclefttype && *amprocrighttype)
   13935          68 :             appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
   13936             : 
   13937          68 :         appendPQExpBuffer(q, " %s", amproc);
   13938             : 
   13939          68 :         needComma = true;
   13940             :     }
   13941             : 
   13942        1296 :     PQclear(res);
   13943             : 
   13944             :     /*
   13945             :      * If needComma is still false it means we haven't added anything after
   13946             :      * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
   13947             :      * clause with the same datatype.  This isn't sanctioned by the
   13948             :      * documentation, but actually DefineOpClass will treat it as a no-op.
   13949             :      */
   13950        1296 :     if (!needComma)
   13951         636 :         appendPQExpBuffer(q, "STORAGE %s", opcintype);
   13952             : 
   13953        1296 :     appendPQExpBufferStr(q, ";\n");
   13954             : 
   13955        1296 :     appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
   13956        1296 :     appendPQExpBuffer(nameusing, " USING %s",
   13957             :                       fmtId(amname));
   13958             : 
   13959        1296 :     if (dopt->binary_upgrade)
   13960          12 :         binary_upgrade_extension_member(q, &opcinfo->dobj,
   13961          12 :                                         "OPERATOR CLASS", nameusing->data,
   13962          12 :                                         opcinfo->dobj.namespace->dobj.name);
   13963             : 
   13964        1296 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   13965        1296 :         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
   13966        1296 :                      ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
   13967             :                                   .namespace = opcinfo->dobj.namespace->dobj.name,
   13968             :                                   .owner = opcinfo->rolname,
   13969             :                                   .description = "OPERATOR CLASS",
   13970             :                                   .section = SECTION_PRE_DATA,
   13971             :                                   .createStmt = q->data,
   13972             :                                   .dropStmt = delq->data));
   13973             : 
   13974             :     /* Dump Operator Class Comments */
   13975        1296 :     if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   13976           0 :         dumpComment(fout, "OPERATOR CLASS", nameusing->data,
   13977           0 :                     opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
   13978             :                     opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
   13979             : 
   13980        1296 :     free(opcintype);
   13981        1296 :     free(opcfamily);
   13982        1296 :     free(amname);
   13983        1296 :     destroyPQExpBuffer(query);
   13984        1296 :     destroyPQExpBuffer(q);
   13985        1296 :     destroyPQExpBuffer(delq);
   13986        1296 :     destroyPQExpBuffer(nameusing);
   13987             : }
   13988             : 
   13989             : /*
   13990             :  * dumpOpfamily
   13991             :  *    write out a single operator family definition
   13992             :  *
   13993             :  * Note: this also dumps any "loose" operator members that aren't bound to a
   13994             :  * specific opclass within the opfamily.
   13995             :  */
   13996             : static void
   13997        1106 : dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
   13998             : {
   13999        1106 :     DumpOptions *dopt = fout->dopt;
   14000             :     PQExpBuffer query;
   14001             :     PQExpBuffer q;
   14002             :     PQExpBuffer delq;
   14003             :     PQExpBuffer nameusing;
   14004             :     PGresult   *res;
   14005             :     PGresult   *res_ops;
   14006             :     PGresult   *res_procs;
   14007             :     int         ntups;
   14008             :     int         i_amname;
   14009             :     int         i_amopstrategy;
   14010             :     int         i_amopopr;
   14011             :     int         i_sortfamily;
   14012             :     int         i_sortfamilynsp;
   14013             :     int         i_amprocnum;
   14014             :     int         i_amproc;
   14015             :     int         i_amproclefttype;
   14016             :     int         i_amprocrighttype;
   14017             :     char       *amname;
   14018             :     char       *amopstrategy;
   14019             :     char       *amopopr;
   14020             :     char       *sortfamily;
   14021             :     char       *sortfamilynsp;
   14022             :     char       *amprocnum;
   14023             :     char       *amproc;
   14024             :     char       *amproclefttype;
   14025             :     char       *amprocrighttype;
   14026             :     bool        needComma;
   14027             :     int         i;
   14028             : 
   14029             :     /* Do nothing if not dumping schema */
   14030        1106 :     if (!dopt->dumpSchema)
   14031          24 :         return;
   14032             : 
   14033        1082 :     query = createPQExpBuffer();
   14034        1082 :     q = createPQExpBuffer();
   14035        1082 :     delq = createPQExpBuffer();
   14036        1082 :     nameusing = createPQExpBuffer();
   14037             : 
   14038             :     /*
   14039             :      * Fetch only those opfamily members that are tied directly to the
   14040             :      * opfamily by pg_depend entries.
   14041             :      */
   14042        1082 :     appendPQExpBuffer(query, "SELECT amopstrategy, "
   14043             :                       "amopopr::pg_catalog.regoperator, "
   14044             :                       "opfname AS sortfamily, "
   14045             :                       "nspname AS sortfamilynsp "
   14046             :                       "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
   14047             :                       "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
   14048             :                       "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
   14049             :                       "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
   14050             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14051             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14052             :                       "AND amopfamily = '%u'::pg_catalog.oid "
   14053             :                       "ORDER BY amopstrategy",
   14054             :                       opfinfo->dobj.catId.oid,
   14055             :                       opfinfo->dobj.catId.oid);
   14056             : 
   14057        1082 :     res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14058             : 
   14059        1082 :     resetPQExpBuffer(query);
   14060             : 
   14061        1082 :     appendPQExpBuffer(query, "SELECT amprocnum, "
   14062             :                       "amproc::pg_catalog.regprocedure, "
   14063             :                       "amproclefttype::pg_catalog.regtype, "
   14064             :                       "amprocrighttype::pg_catalog.regtype "
   14065             :                       "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
   14066             :                       "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
   14067             :                       "AND refobjid = '%u'::pg_catalog.oid "
   14068             :                       "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
   14069             :                       "AND objid = ap.oid "
   14070             :                       "ORDER BY amprocnum",
   14071             :                       opfinfo->dobj.catId.oid);
   14072             : 
   14073        1082 :     res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   14074             : 
   14075             :     /* Get additional fields from the pg_opfamily row */
   14076        1082 :     resetPQExpBuffer(query);
   14077             : 
   14078        1082 :     appendPQExpBuffer(query, "SELECT "
   14079             :                       "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
   14080             :                       "FROM pg_catalog.pg_opfamily "
   14081             :                       "WHERE oid = '%u'::pg_catalog.oid",
   14082             :                       opfinfo->dobj.catId.oid);
   14083             : 
   14084        1082 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14085             : 
   14086        1082 :     i_amname = PQfnumber(res, "amname");
   14087             : 
   14088             :     /* amname will still be needed after we PQclear res */
   14089        1082 :     amname = pg_strdup(PQgetvalue(res, 0, i_amname));
   14090             : 
   14091        1082 :     appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
   14092        1082 :                       fmtQualifiedDumpable(opfinfo));
   14093        1082 :     appendPQExpBuffer(delq, " USING %s;\n",
   14094             :                       fmtId(amname));
   14095             : 
   14096             :     /* Build the fixed portion of the CREATE command */
   14097        1082 :     appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
   14098        1082 :                       fmtQualifiedDumpable(opfinfo));
   14099        1082 :     appendPQExpBuffer(q, " USING %s;\n",
   14100             :                       fmtId(amname));
   14101             : 
   14102        1082 :     PQclear(res);
   14103             : 
   14104             :     /* Do we need an ALTER to add loose members? */
   14105        1082 :     if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
   14106             :     {
   14107          98 :         appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
   14108          98 :                           fmtQualifiedDumpable(opfinfo));
   14109          98 :         appendPQExpBuffer(q, " USING %s ADD\n    ",
   14110             :                           fmtId(amname));
   14111             : 
   14112          98 :         needComma = false;
   14113             : 
   14114             :         /*
   14115             :          * Now fetch and print the OPERATOR entries (pg_amop rows).
   14116             :          */
   14117          98 :         ntups = PQntuples(res_ops);
   14118             : 
   14119          98 :         i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
   14120          98 :         i_amopopr = PQfnumber(res_ops, "amopopr");
   14121          98 :         i_sortfamily = PQfnumber(res_ops, "sortfamily");
   14122          98 :         i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
   14123             : 
   14124         438 :         for (i = 0; i < ntups; i++)
   14125             :         {
   14126         340 :             amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
   14127         340 :             amopopr = PQgetvalue(res_ops, i, i_amopopr);
   14128         340 :             sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
   14129         340 :             sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
   14130             : 
   14131         340 :             if (needComma)
   14132         272 :                 appendPQExpBufferStr(q, " ,\n    ");
   14133             : 
   14134         340 :             appendPQExpBuffer(q, "OPERATOR %s %s",
   14135             :                               amopstrategy, amopopr);
   14136             : 
   14137         340 :             if (strlen(sortfamily) > 0)
   14138             :             {
   14139           0 :                 appendPQExpBufferStr(q, " FOR ORDER BY ");
   14140           0 :                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
   14141           0 :                 appendPQExpBufferStr(q, fmtId(sortfamily));
   14142             :             }
   14143             : 
   14144         340 :             needComma = true;
   14145             :         }
   14146             : 
   14147             :         /*
   14148             :          * Now fetch and print the FUNCTION entries (pg_amproc rows).
   14149             :          */
   14150          98 :         ntups = PQntuples(res_procs);
   14151             : 
   14152          98 :         i_amprocnum = PQfnumber(res_procs, "amprocnum");
   14153          98 :         i_amproc = PQfnumber(res_procs, "amproc");
   14154          98 :         i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
   14155          98 :         i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
   14156             : 
   14157         468 :         for (i = 0; i < ntups; i++)
   14158             :         {
   14159         370 :             amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
   14160         370 :             amproc = PQgetvalue(res_procs, i, i_amproc);
   14161         370 :             amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
   14162         370 :             amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
   14163             : 
   14164         370 :             if (needComma)
   14165         340 :                 appendPQExpBufferStr(q, " ,\n    ");
   14166             : 
   14167         370 :             appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
   14168             :                               amprocnum, amproclefttype, amprocrighttype,
   14169             :                               amproc);
   14170             : 
   14171         370 :             needComma = true;
   14172             :         }
   14173             : 
   14174          98 :         appendPQExpBufferStr(q, ";\n");
   14175             :     }
   14176             : 
   14177        1082 :     appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
   14178        1082 :     appendPQExpBuffer(nameusing, " USING %s",
   14179             :                       fmtId(amname));
   14180             : 
   14181        1082 :     if (dopt->binary_upgrade)
   14182          18 :         binary_upgrade_extension_member(q, &opfinfo->dobj,
   14183          18 :                                         "OPERATOR FAMILY", nameusing->data,
   14184          18 :                                         opfinfo->dobj.namespace->dobj.name);
   14185             : 
   14186        1082 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14187        1082 :         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
   14188        1082 :                      ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
   14189             :                                   .namespace = opfinfo->dobj.namespace->dobj.name,
   14190             :                                   .owner = opfinfo->rolname,
   14191             :                                   .description = "OPERATOR FAMILY",
   14192             :                                   .section = SECTION_PRE_DATA,
   14193             :                                   .createStmt = q->data,
   14194             :                                   .dropStmt = delq->data));
   14195             : 
   14196             :     /* Dump Operator Family Comments */
   14197        1082 :     if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14198           0 :         dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
   14199           0 :                     opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
   14200             :                     opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
   14201             : 
   14202        1082 :     free(amname);
   14203        1082 :     PQclear(res_ops);
   14204        1082 :     PQclear(res_procs);
   14205        1082 :     destroyPQExpBuffer(query);
   14206        1082 :     destroyPQExpBuffer(q);
   14207        1082 :     destroyPQExpBuffer(delq);
   14208        1082 :     destroyPQExpBuffer(nameusing);
   14209             : }
   14210             : 
   14211             : /*
   14212             :  * dumpCollation
   14213             :  *    write out a single collation definition
   14214             :  */
   14215             : static void
   14216        4944 : dumpCollation(Archive *fout, const CollInfo *collinfo)
   14217             : {
   14218        4944 :     DumpOptions *dopt = fout->dopt;
   14219             :     PQExpBuffer query;
   14220             :     PQExpBuffer q;
   14221             :     PQExpBuffer delq;
   14222             :     char       *qcollname;
   14223             :     PGresult   *res;
   14224             :     int         i_collprovider;
   14225             :     int         i_collisdeterministic;
   14226             :     int         i_collcollate;
   14227             :     int         i_collctype;
   14228             :     int         i_colllocale;
   14229             :     int         i_collicurules;
   14230             :     const char *collprovider;
   14231             :     const char *collcollate;
   14232             :     const char *collctype;
   14233             :     const char *colllocale;
   14234             :     const char *collicurules;
   14235             : 
   14236             :     /* Do nothing if not dumping schema */
   14237        4944 :     if (!dopt->dumpSchema)
   14238          24 :         return;
   14239             : 
   14240        4920 :     query = createPQExpBuffer();
   14241        4920 :     q = createPQExpBuffer();
   14242        4920 :     delq = createPQExpBuffer();
   14243             : 
   14244        4920 :     qcollname = pg_strdup(fmtId(collinfo->dobj.name));
   14245             : 
   14246             :     /* Get collation-specific details */
   14247        4920 :     appendPQExpBufferStr(query, "SELECT ");
   14248             : 
   14249        4920 :     if (fout->remoteVersion >= 100000)
   14250        4920 :         appendPQExpBufferStr(query,
   14251             :                              "collprovider, "
   14252             :                              "collversion, ");
   14253             :     else
   14254           0 :         appendPQExpBufferStr(query,
   14255             :                              "'c' AS collprovider, "
   14256             :                              "NULL AS collversion, ");
   14257             : 
   14258        4920 :     if (fout->remoteVersion >= 120000)
   14259        4920 :         appendPQExpBufferStr(query,
   14260             :                              "collisdeterministic, ");
   14261             :     else
   14262           0 :         appendPQExpBufferStr(query,
   14263             :                              "true AS collisdeterministic, ");
   14264             : 
   14265        4920 :     if (fout->remoteVersion >= 170000)
   14266        4920 :         appendPQExpBufferStr(query,
   14267             :                              "colllocale, ");
   14268           0 :     else if (fout->remoteVersion >= 150000)
   14269           0 :         appendPQExpBufferStr(query,
   14270             :                              "colliculocale AS colllocale, ");
   14271             :     else
   14272           0 :         appendPQExpBufferStr(query,
   14273             :                              "NULL AS colllocale, ");
   14274             : 
   14275        4920 :     if (fout->remoteVersion >= 160000)
   14276        4920 :         appendPQExpBufferStr(query,
   14277             :                              "collicurules, ");
   14278             :     else
   14279           0 :         appendPQExpBufferStr(query,
   14280             :                              "NULL AS collicurules, ");
   14281             : 
   14282        4920 :     appendPQExpBuffer(query,
   14283             :                       "collcollate, "
   14284             :                       "collctype "
   14285             :                       "FROM pg_catalog.pg_collation c "
   14286             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14287             :                       collinfo->dobj.catId.oid);
   14288             : 
   14289        4920 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14290             : 
   14291        4920 :     i_collprovider = PQfnumber(res, "collprovider");
   14292        4920 :     i_collisdeterministic = PQfnumber(res, "collisdeterministic");
   14293        4920 :     i_collcollate = PQfnumber(res, "collcollate");
   14294        4920 :     i_collctype = PQfnumber(res, "collctype");
   14295        4920 :     i_colllocale = PQfnumber(res, "colllocale");
   14296        4920 :     i_collicurules = PQfnumber(res, "collicurules");
   14297             : 
   14298        4920 :     collprovider = PQgetvalue(res, 0, i_collprovider);
   14299             : 
   14300        4920 :     if (!PQgetisnull(res, 0, i_collcollate))
   14301          96 :         collcollate = PQgetvalue(res, 0, i_collcollate);
   14302             :     else
   14303        4824 :         collcollate = NULL;
   14304             : 
   14305        4920 :     if (!PQgetisnull(res, 0, i_collctype))
   14306          96 :         collctype = PQgetvalue(res, 0, i_collctype);
   14307             :     else
   14308        4824 :         collctype = NULL;
   14309             : 
   14310             :     /*
   14311             :      * Before version 15, collcollate and collctype were of type NAME and
   14312             :      * non-nullable. Treat empty strings as NULL for consistency.
   14313             :      */
   14314        4920 :     if (fout->remoteVersion < 150000)
   14315             :     {
   14316           0 :         if (collcollate[0] == '\0')
   14317           0 :             collcollate = NULL;
   14318           0 :         if (collctype[0] == '\0')
   14319           0 :             collctype = NULL;
   14320             :     }
   14321             : 
   14322        4920 :     if (!PQgetisnull(res, 0, i_colllocale))
   14323        4818 :         colllocale = PQgetvalue(res, 0, i_colllocale);
   14324             :     else
   14325         102 :         colllocale = NULL;
   14326             : 
   14327        4920 :     if (!PQgetisnull(res, 0, i_collicurules))
   14328           0 :         collicurules = PQgetvalue(res, 0, i_collicurules);
   14329             :     else
   14330        4920 :         collicurules = NULL;
   14331             : 
   14332        4920 :     appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
   14333        4920 :                       fmtQualifiedDumpable(collinfo));
   14334             : 
   14335        4920 :     appendPQExpBuffer(q, "CREATE COLLATION %s (",
   14336        4920 :                       fmtQualifiedDumpable(collinfo));
   14337             : 
   14338        4920 :     appendPQExpBufferStr(q, "provider = ");
   14339        4920 :     if (collprovider[0] == 'b')
   14340          38 :         appendPQExpBufferStr(q, "builtin");
   14341        4882 :     else if (collprovider[0] == 'c')
   14342          96 :         appendPQExpBufferStr(q, "libc");
   14343        4786 :     else if (collprovider[0] == 'i')
   14344        4780 :         appendPQExpBufferStr(q, "icu");
   14345           6 :     else if (collprovider[0] == 'd')
   14346             :         /* to allow dumping pg_catalog; not accepted on input */
   14347           6 :         appendPQExpBufferStr(q, "default");
   14348             :     else
   14349           0 :         pg_fatal("unrecognized collation provider: %s",
   14350             :                  collprovider);
   14351             : 
   14352        4920 :     if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
   14353           0 :         appendPQExpBufferStr(q, ", deterministic = false");
   14354             : 
   14355        4920 :     if (collprovider[0] == 'd')
   14356             :     {
   14357           6 :         if (collcollate || collctype || colllocale || collicurules)
   14358           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14359             : 
   14360             :         /* no locale -- the default collation cannot be reloaded anyway */
   14361             :     }
   14362        4914 :     else if (collprovider[0] == 'b')
   14363             :     {
   14364          38 :         if (collcollate || collctype || !colllocale || collicurules)
   14365           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14366             : 
   14367          38 :         appendPQExpBufferStr(q, ", locale = ");
   14368          38 :         appendStringLiteralAH(q, colllocale ? colllocale : "",
   14369             :                               fout);
   14370             :     }
   14371        4876 :     else if (collprovider[0] == 'i')
   14372             :     {
   14373        4780 :         if (fout->remoteVersion >= 150000)
   14374             :         {
   14375        4780 :             if (collcollate || collctype || !colllocale)
   14376           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   14377             : 
   14378        4780 :             appendPQExpBufferStr(q, ", locale = ");
   14379        4780 :             appendStringLiteralAH(q, colllocale ? colllocale : "",
   14380             :                                   fout);
   14381             :         }
   14382             :         else
   14383             :         {
   14384           0 :             if (!collcollate || !collctype || colllocale ||
   14385           0 :                 strcmp(collcollate, collctype) != 0)
   14386           0 :                 pg_log_warning("invalid collation \"%s\"", qcollname);
   14387             : 
   14388           0 :             appendPQExpBufferStr(q, ", locale = ");
   14389           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14390             :         }
   14391             : 
   14392        4780 :         if (collicurules)
   14393             :         {
   14394           0 :             appendPQExpBufferStr(q, ", rules = ");
   14395           0 :             appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
   14396             :         }
   14397             :     }
   14398          96 :     else if (collprovider[0] == 'c')
   14399             :     {
   14400          96 :         if (colllocale || collicurules || !collcollate || !collctype)
   14401           0 :             pg_log_warning("invalid collation \"%s\"", qcollname);
   14402             : 
   14403          96 :         if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
   14404             :         {
   14405          96 :             appendPQExpBufferStr(q, ", locale = ");
   14406          96 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14407             :         }
   14408             :         else
   14409             :         {
   14410           0 :             appendPQExpBufferStr(q, ", lc_collate = ");
   14411           0 :             appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
   14412           0 :             appendPQExpBufferStr(q, ", lc_ctype = ");
   14413           0 :             appendStringLiteralAH(q, collctype ? collctype : "", fout);
   14414             :         }
   14415             :     }
   14416             :     else
   14417           0 :         pg_fatal("unrecognized collation provider: %s", collprovider);
   14418             : 
   14419             :     /*
   14420             :      * For binary upgrade, carry over the collation version.  For normal
   14421             :      * dump/restore, omit the version, so that it is computed upon restore.
   14422             :      */
   14423        4920 :     if (dopt->binary_upgrade)
   14424             :     {
   14425             :         int         i_collversion;
   14426             : 
   14427          10 :         i_collversion = PQfnumber(res, "collversion");
   14428          10 :         if (!PQgetisnull(res, 0, i_collversion))
   14429             :         {
   14430           8 :             appendPQExpBufferStr(q, ", version = ");
   14431           8 :             appendStringLiteralAH(q,
   14432             :                                   PQgetvalue(res, 0, i_collversion),
   14433             :                                   fout);
   14434             :         }
   14435             :     }
   14436             : 
   14437        4920 :     appendPQExpBufferStr(q, ");\n");
   14438             : 
   14439        4920 :     if (dopt->binary_upgrade)
   14440          10 :         binary_upgrade_extension_member(q, &collinfo->dobj,
   14441             :                                         "COLLATION", qcollname,
   14442          10 :                                         collinfo->dobj.namespace->dobj.name);
   14443             : 
   14444        4920 :     if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14445        4920 :         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
   14446        4920 :                      ARCHIVE_OPTS(.tag = collinfo->dobj.name,
   14447             :                                   .namespace = collinfo->dobj.namespace->dobj.name,
   14448             :                                   .owner = collinfo->rolname,
   14449             :                                   .description = "COLLATION",
   14450             :                                   .section = SECTION_PRE_DATA,
   14451             :                                   .createStmt = q->data,
   14452             :                                   .dropStmt = delq->data));
   14453             : 
   14454             :     /* Dump Collation Comments */
   14455        4920 :     if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14456        4740 :         dumpComment(fout, "COLLATION", qcollname,
   14457        4740 :                     collinfo->dobj.namespace->dobj.name, collinfo->rolname,
   14458             :                     collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
   14459             : 
   14460        4920 :     PQclear(res);
   14461             : 
   14462        4920 :     destroyPQExpBuffer(query);
   14463        4920 :     destroyPQExpBuffer(q);
   14464        4920 :     destroyPQExpBuffer(delq);
   14465        4920 :     free(qcollname);
   14466             : }
   14467             : 
   14468             : /*
   14469             :  * dumpConversion
   14470             :  *    write out a single conversion definition
   14471             :  */
   14472             : static void
   14473         848 : dumpConversion(Archive *fout, const ConvInfo *convinfo)
   14474             : {
   14475         848 :     DumpOptions *dopt = fout->dopt;
   14476             :     PQExpBuffer query;
   14477             :     PQExpBuffer q;
   14478             :     PQExpBuffer delq;
   14479             :     char       *qconvname;
   14480             :     PGresult   *res;
   14481             :     int         i_conforencoding;
   14482             :     int         i_contoencoding;
   14483             :     int         i_conproc;
   14484             :     int         i_condefault;
   14485             :     const char *conforencoding;
   14486             :     const char *contoencoding;
   14487             :     const char *conproc;
   14488             :     bool        condefault;
   14489             : 
   14490             :     /* Do nothing if not dumping schema */
   14491         848 :     if (!dopt->dumpSchema)
   14492          12 :         return;
   14493             : 
   14494         836 :     query = createPQExpBuffer();
   14495         836 :     q = createPQExpBuffer();
   14496         836 :     delq = createPQExpBuffer();
   14497             : 
   14498         836 :     qconvname = pg_strdup(fmtId(convinfo->dobj.name));
   14499             : 
   14500             :     /* Get conversion-specific details */
   14501         836 :     appendPQExpBuffer(query, "SELECT "
   14502             :                       "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
   14503             :                       "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
   14504             :                       "conproc, condefault "
   14505             :                       "FROM pg_catalog.pg_conversion c "
   14506             :                       "WHERE c.oid = '%u'::pg_catalog.oid",
   14507             :                       convinfo->dobj.catId.oid);
   14508             : 
   14509         836 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14510             : 
   14511         836 :     i_conforencoding = PQfnumber(res, "conforencoding");
   14512         836 :     i_contoencoding = PQfnumber(res, "contoencoding");
   14513         836 :     i_conproc = PQfnumber(res, "conproc");
   14514         836 :     i_condefault = PQfnumber(res, "condefault");
   14515             : 
   14516         836 :     conforencoding = PQgetvalue(res, 0, i_conforencoding);
   14517         836 :     contoencoding = PQgetvalue(res, 0, i_contoencoding);
   14518         836 :     conproc = PQgetvalue(res, 0, i_conproc);
   14519         836 :     condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
   14520             : 
   14521         836 :     appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
   14522         836 :                       fmtQualifiedDumpable(convinfo));
   14523             : 
   14524         836 :     appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
   14525             :                       (condefault) ? "DEFAULT " : "",
   14526         836 :                       fmtQualifiedDumpable(convinfo));
   14527         836 :     appendStringLiteralAH(q, conforencoding, fout);
   14528         836 :     appendPQExpBufferStr(q, " TO ");
   14529         836 :     appendStringLiteralAH(q, contoencoding, fout);
   14530             :     /* regproc output is already sufficiently quoted */
   14531         836 :     appendPQExpBuffer(q, " FROM %s;\n", conproc);
   14532             : 
   14533         836 :     if (dopt->binary_upgrade)
   14534           2 :         binary_upgrade_extension_member(q, &convinfo->dobj,
   14535             :                                         "CONVERSION", qconvname,
   14536           2 :                                         convinfo->dobj.namespace->dobj.name);
   14537             : 
   14538         836 :     if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   14539         836 :         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
   14540         836 :                      ARCHIVE_OPTS(.tag = convinfo->dobj.name,
   14541             :                                   .namespace = convinfo->dobj.namespace->dobj.name,
   14542             :                                   .owner = convinfo->rolname,
   14543             :                                   .description = "CONVERSION",
   14544             :                                   .section = SECTION_PRE_DATA,
   14545             :                                   .createStmt = q->data,
   14546             :                                   .dropStmt = delq->data));
   14547             : 
   14548             :     /* Dump Conversion Comments */
   14549         836 :     if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   14550         836 :         dumpComment(fout, "CONVERSION", qconvname,
   14551         836 :                     convinfo->dobj.namespace->dobj.name, convinfo->rolname,
   14552             :                     convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
   14553             : 
   14554         836 :     PQclear(res);
   14555             : 
   14556         836 :     destroyPQExpBuffer(query);
   14557         836 :     destroyPQExpBuffer(q);
   14558         836 :     destroyPQExpBuffer(delq);
   14559         836 :     free(qconvname);
   14560             : }
   14561             : 
   14562             : /*
   14563             :  * format_aggregate_signature: generate aggregate name and argument list
   14564             :  *
   14565             :  * The argument type names are qualified if needed.  The aggregate name
   14566             :  * is never qualified.
   14567             :  */
   14568             : static char *
   14569         574 : format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
   14570             : {
   14571             :     PQExpBufferData buf;
   14572             :     int         j;
   14573             : 
   14574         574 :     initPQExpBuffer(&buf);
   14575         574 :     if (honor_quotes)
   14576           0 :         appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
   14577             :     else
   14578         574 :         appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
   14579             : 
   14580         574 :     if (agginfo->aggfn.nargs == 0)
   14581          80 :         appendPQExpBufferStr(&buf, "(*)");
   14582             :     else
   14583             :     {
   14584         494 :         appendPQExpBufferChar(&buf, '(');
   14585        1078 :         for (j = 0; j < agginfo->aggfn.nargs; j++)
   14586         584 :             appendPQExpBuffer(&buf, "%s%s",
   14587             :                               (j > 0) ? ", " : "",
   14588             :                               getFormattedTypeName(fout,
   14589         584 :                                                    agginfo->aggfn.argtypes[j],
   14590             :                                                    zeroIsError));
   14591         494 :         appendPQExpBufferChar(&buf, ')');
   14592             :     }
   14593         574 :     return buf.data;
   14594             : }
   14595             : 
   14596             : /*
   14597             :  * dumpAgg
   14598             :  *    write out a single aggregate definition
   14599             :  */
   14600             : static void
   14601         588 : dumpAgg(Archive *fout, const AggInfo *agginfo)
   14602             : {
   14603         588 :     DumpOptions *dopt = fout->dopt;
   14604             :     PQExpBuffer query;
   14605             :     PQExpBuffer q;
   14606             :     PQExpBuffer delq;
   14607             :     PQExpBuffer details;
   14608             :     char       *aggsig;         /* identity signature */
   14609         588 :     char       *aggfullsig = NULL;  /* full signature */
   14610             :     char       *aggsig_tag;
   14611             :     PGresult   *res;
   14612             :     int         i_agginitval;
   14613             :     int         i_aggminitval;
   14614             :     const char *aggtransfn;
   14615             :     const char *aggfinalfn;
   14616             :     const char *aggcombinefn;
   14617             :     const char *aggserialfn;
   14618             :     const char *aggdeserialfn;
   14619             :     const char *aggmtransfn;
   14620             :     const char *aggminvtransfn;
   14621             :     const char *aggmfinalfn;
   14622             :     bool        aggfinalextra;
   14623             :     bool        aggmfinalextra;
   14624             :     char        aggfinalmodify;
   14625             :     char        aggmfinalmodify;
   14626             :     const char *aggsortop;
   14627             :     char       *aggsortconvop;
   14628             :     char        aggkind;
   14629             :     const char *aggtranstype;
   14630             :     const char *aggtransspace;
   14631             :     const char *aggmtranstype;
   14632             :     const char *aggmtransspace;
   14633             :     const char *agginitval;
   14634             :     const char *aggminitval;
   14635             :     const char *proparallel;
   14636             :     char        defaultfinalmodify;
   14637             : 
   14638             :     /* Do nothing if not dumping schema */
   14639         588 :     if (!dopt->dumpSchema)
   14640          14 :         return;
   14641             : 
   14642         574 :     query = createPQExpBuffer();
   14643         574 :     q = createPQExpBuffer();
   14644         574 :     delq = createPQExpBuffer();
   14645         574 :     details = createPQExpBuffer();
   14646             : 
   14647         574 :     if (!fout->is_prepared[PREPQUERY_DUMPAGG])
   14648             :     {
   14649             :         /* Set up query for aggregate-specific details */
   14650         114 :         appendPQExpBufferStr(query,
   14651             :                              "PREPARE dumpAgg(pg_catalog.oid) AS\n");
   14652             : 
   14653         114 :         appendPQExpBufferStr(query,
   14654             :                              "SELECT "
   14655             :                              "aggtransfn,\n"
   14656             :                              "aggfinalfn,\n"
   14657             :                              "aggtranstype::pg_catalog.regtype,\n"
   14658             :                              "agginitval,\n"
   14659             :                              "aggsortop,\n"
   14660             :                              "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
   14661             :                              "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
   14662             : 
   14663         114 :         if (fout->remoteVersion >= 90400)
   14664         114 :             appendPQExpBufferStr(query,
   14665             :                                  "aggkind,\n"
   14666             :                                  "aggmtransfn,\n"
   14667             :                                  "aggminvtransfn,\n"
   14668             :                                  "aggmfinalfn,\n"
   14669             :                                  "aggmtranstype::pg_catalog.regtype,\n"
   14670             :                                  "aggfinalextra,\n"
   14671             :                                  "aggmfinalextra,\n"
   14672             :                                  "aggtransspace,\n"
   14673             :                                  "aggmtransspace,\n"
   14674             :                                  "aggminitval,\n");
   14675             :         else
   14676           0 :             appendPQExpBufferStr(query,
   14677             :                                  "'n' AS aggkind,\n"
   14678             :                                  "'-' AS aggmtransfn,\n"
   14679             :                                  "'-' AS aggminvtransfn,\n"
   14680             :                                  "'-' AS aggmfinalfn,\n"
   14681             :                                  "0 AS aggmtranstype,\n"
   14682             :                                  "false AS aggfinalextra,\n"
   14683             :                                  "false AS aggmfinalextra,\n"
   14684             :                                  "0 AS aggtransspace,\n"
   14685             :                                  "0 AS aggmtransspace,\n"
   14686             :                                  "NULL AS aggminitval,\n");
   14687             : 
   14688         114 :         if (fout->remoteVersion >= 90600)
   14689         114 :             appendPQExpBufferStr(query,
   14690             :                                  "aggcombinefn,\n"
   14691             :                                  "aggserialfn,\n"
   14692             :                                  "aggdeserialfn,\n"
   14693             :                                  "proparallel,\n");
   14694             :         else
   14695           0 :             appendPQExpBufferStr(query,
   14696             :                                  "'-' AS aggcombinefn,\n"
   14697             :                                  "'-' AS aggserialfn,\n"
   14698             :                                  "'-' AS aggdeserialfn,\n"
   14699             :                                  "'u' AS proparallel,\n");
   14700             : 
   14701         114 :         if (fout->remoteVersion >= 110000)
   14702         114 :             appendPQExpBufferStr(query,
   14703             :                                  "aggfinalmodify,\n"
   14704             :                                  "aggmfinalmodify\n");
   14705             :         else
   14706           0 :             appendPQExpBufferStr(query,
   14707             :                                  "'0' AS aggfinalmodify,\n"
   14708             :                                  "'0' AS aggmfinalmodify\n");
   14709             : 
   14710         114 :         appendPQExpBufferStr(query,
   14711             :                              "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
   14712             :                              "WHERE a.aggfnoid = p.oid "
   14713             :                              "AND p.oid = $1");
   14714             : 
   14715         114 :         ExecuteSqlStatement(fout, query->data);
   14716             : 
   14717         114 :         fout->is_prepared[PREPQUERY_DUMPAGG] = true;
   14718             :     }
   14719             : 
   14720         574 :     printfPQExpBuffer(query,
   14721             :                       "EXECUTE dumpAgg('%u')",
   14722             :                       agginfo->aggfn.dobj.catId.oid);
   14723             : 
   14724         574 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   14725             : 
   14726         574 :     i_agginitval = PQfnumber(res, "agginitval");
   14727         574 :     i_aggminitval = PQfnumber(res, "aggminitval");
   14728             : 
   14729         574 :     aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
   14730         574 :     aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
   14731         574 :     aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
   14732         574 :     aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
   14733         574 :     aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
   14734         574 :     aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
   14735         574 :     aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
   14736         574 :     aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
   14737         574 :     aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
   14738         574 :     aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
   14739         574 :     aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
   14740         574 :     aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
   14741         574 :     aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
   14742         574 :     aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
   14743         574 :     aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
   14744         574 :     aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
   14745         574 :     aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
   14746         574 :     aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
   14747         574 :     agginitval = PQgetvalue(res, 0, i_agginitval);
   14748         574 :     aggminitval = PQgetvalue(res, 0, i_aggminitval);
   14749         574 :     proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
   14750             : 
   14751             :     {
   14752             :         char       *funcargs;
   14753             :         char       *funciargs;
   14754             : 
   14755         574 :         funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
   14756         574 :         funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
   14757         574 :         aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
   14758         574 :         aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
   14759             :     }
   14760             : 
   14761         574 :     aggsig_tag = format_aggregate_signature(agginfo, fout, false);
   14762             : 
   14763             :     /* identify default modify flag for aggkind (must match DefineAggregate) */
   14764         574 :     defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
   14765             :     /* replace omitted flags for old versions */
   14766         574 :     if (aggfinalmodify == '0')
   14767           0 :         aggfinalmodify = defaultfinalmodify;
   14768         574 :     if (aggmfinalmodify == '0')
   14769           0 :         aggmfinalmodify = defaultfinalmodify;
   14770             : 
   14771             :     /* regproc and regtype output is already sufficiently quoted */
   14772         574 :     appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
   14773             :                       aggtransfn, aggtranstype);
   14774             : 
   14775         574 :     if (strcmp(aggtransspace, "0") != 0)
   14776             :     {
   14777          10 :         appendPQExpBuffer(details, ",\n    SSPACE = %s",
   14778             :                           aggtransspace);
   14779             :     }
   14780             : 
   14781         574 :     if (!PQgetisnull(res, 0, i_agginitval))
   14782             :     {
   14783         418 :         appendPQExpBufferStr(details, ",\n    INITCOND = ");
   14784         418 :         appendStringLiteralAH(details, agginitval, fout);
   14785             :     }
   14786             : 
   14787         574 :     if (strcmp(aggfinalfn, "-") != 0)
   14788             :     {
   14789         268 :         appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
   14790             :                           aggfinalfn);
   14791         268 :         if (aggfinalextra)
   14792          20 :             appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
   14793         268 :         if (aggfinalmodify != defaultfinalmodify)
   14794             :         {
   14795          68 :             switch (aggfinalmodify)
   14796             :             {
   14797           0 :                 case AGGMODIFY_READ_ONLY:
   14798           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
   14799           0 :                     break;
   14800          68 :                 case AGGMODIFY_SHAREABLE:
   14801          68 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
   14802          68 :                     break;
   14803           0 :                 case AGGMODIFY_READ_WRITE:
   14804           0 :                     appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
   14805           0 :                     break;
   14806           0 :                 default:
   14807           0 :                     pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
   14808             :                              agginfo->aggfn.dobj.name);
   14809             :                     break;
   14810             :             }
   14811         506 :         }
   14812             :     }
   14813             : 
   14814         574 :     if (strcmp(aggcombinefn, "-") != 0)
   14815           0 :         appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
   14816             : 
   14817         574 :     if (strcmp(aggserialfn, "-") != 0)
   14818           0 :         appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
   14819             : 
   14820         574 :     if (strcmp(aggdeserialfn, "-") != 0)
   14821           0 :         appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
   14822             : 
   14823         574 :     if (strcmp(aggmtransfn, "-") != 0)
   14824             :     {
   14825          60 :         appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
   14826             :                           aggmtransfn,
   14827             :                           aggminvtransfn,
   14828             :                           aggmtranstype);
   14829             :     }
   14830             : 
   14831         574 :     if (strcmp(aggmtransspace, "0") != 0)
   14832             :     {
   14833           0 :         appendPQExpBuffer(details, ",\n    MSSPACE = %s",
   14834             :                           aggmtransspace);
   14835             :     }
   14836             : 
   14837         574 :     if (!PQgetisnull(res, 0, i_aggminitval))
   14838             :     {
   14839          20 :         appendPQExpBufferStr(details, ",\n    MINITCOND = ");
   14840          20 :         appendStringLiteralAH(details, aggminitval, fout);
   14841             :     }
   14842             : 
   14843         574 :     if (strcmp(aggmfinalfn, "-") != 0)
   14844             :     {
   14845           0 :         appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
   14846             :                           aggmfinalfn);
   14847           0 :         if (aggmfinalextra)
   14848           0 :             appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
   14849           0 :         if (aggmfinalmodify != defaultfinalmodify)
   14850             :         {
   14851           0 :             switch (aggmfinalmodify)
   14852             :             {
   14853           0 :                 case AGGMODIFY_READ_ONLY:
   14854           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
   14855           0 :                     break;
   14856           0 :                 case AGGMODIFY_SHAREABLE:
   14857           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
   14858           0 :                     break;
   14859           0 :                 case AGGMODIFY_READ_WRITE:
   14860           0 :                     appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
   14861           0 :                     break;
   14862           0 :                 default:
   14863           0 :                     pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
   14864             :                              agginfo->aggfn.dobj.name);
   14865             :                     break;
   14866             :             }
   14867         574 :         }
   14868             :     }
   14869             : 
   14870         574 :     aggsortconvop = getFormattedOperatorName(aggsortop);
   14871         574 :     if (aggsortconvop)
   14872             :     {
   14873           0 :         appendPQExpBuffer(details, ",\n    SORTOP = %s",
   14874             :                           aggsortconvop);
   14875           0 :         free(aggsortconvop);
   14876             :     }
   14877             : 
   14878         574 :     if (aggkind == AGGKIND_HYPOTHETICAL)
   14879          10 :         appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
   14880             : 
   14881         574 :     if (proparallel[0] != PROPARALLEL_UNSAFE)
   14882             :     {
   14883          10 :         if (proparallel[0] == PROPARALLEL_SAFE)
   14884          10 :             appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
   14885           0 :         else if (proparallel[0] == PROPARALLEL_RESTRICTED)
   14886           0 :             appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
   14887           0 :         else if (proparallel[0] != PROPARALLEL_UNSAFE)
   14888           0 :             pg_fatal("unrecognized proparallel value for function \"%s\"",
   14889             :                      agginfo->aggfn.dobj.name);
   14890             :     }
   14891             : 
   14892         574 :     appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
   14893         574 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   14894             :                       aggsig);
   14895             : 
   14896        1148 :     appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
   14897         574 :                       fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
   14898             :                       aggfullsig ? aggfullsig : aggsig, details->data);
   14899             : 
   14900         574 :     if (dopt->binary_upgrade)
   14901          98 :         binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
   14902             :                                         "AGGREGATE", aggsig,
   14903          98 :                                         agginfo->aggfn.dobj.namespace->dobj.name);
   14904             : 
   14905         574 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
   14906         540 :         ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
   14907             :                      agginfo->aggfn.dobj.dumpId,
   14908         540 :                      ARCHIVE_OPTS(.tag = aggsig_tag,
   14909             :                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
   14910             :                                   .owner = agginfo->aggfn.rolname,
   14911             :                                   .description = "AGGREGATE",
   14912             :                                   .section = SECTION_PRE_DATA,
   14913             :                                   .createStmt = q->data,
   14914             :                                   .dropStmt = delq->data));
   14915             : 
   14916             :     /* Dump Aggregate Comments */
   14917         574 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
   14918          20 :         dumpComment(fout, "AGGREGATE", aggsig,
   14919          20 :                     agginfo->aggfn.dobj.namespace->dobj.name,
   14920             :                     agginfo->aggfn.rolname,
   14921             :                     agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   14922             : 
   14923         574 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
   14924           0 :         dumpSecLabel(fout, "AGGREGATE", aggsig,
   14925           0 :                      agginfo->aggfn.dobj.namespace->dobj.name,
   14926             :                      agginfo->aggfn.rolname,
   14927             :                      agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
   14928             : 
   14929             :     /*
   14930             :      * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
   14931             :      * command look like a function's GRANT; in particular this affects the
   14932             :      * syntax for zero-argument aggregates and ordered-set aggregates.
   14933             :      */
   14934         574 :     free(aggsig);
   14935             : 
   14936         574 :     aggsig = format_function_signature(fout, &agginfo->aggfn, true);
   14937             : 
   14938         574 :     if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
   14939          36 :         dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
   14940             :                 "FUNCTION", aggsig, NULL,
   14941          36 :                 agginfo->aggfn.dobj.namespace->dobj.name,
   14942             :                 NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
   14943             : 
   14944         574 :     free(aggsig);
   14945         574 :     free(aggfullsig);
   14946         574 :     free(aggsig_tag);
   14947             : 
   14948         574 :     PQclear(res);
   14949             : 
   14950         574 :     destroyPQExpBuffer(query);
   14951         574 :     destroyPQExpBuffer(q);
   14952         574 :     destroyPQExpBuffer(delq);
   14953         574 :     destroyPQExpBuffer(details);
   14954             : }
   14955             : 
   14956             : /*
   14957             :  * dumpTSParser
   14958             :  *    write out a single text search parser
   14959             :  */
   14960             : static void
   14961          86 : dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
   14962             : {
   14963          86 :     DumpOptions *dopt = fout->dopt;
   14964             :     PQExpBuffer q;
   14965             :     PQExpBuffer delq;
   14966             :     char       *qprsname;
   14967             : 
   14968             :     /* Do nothing if not dumping schema */
   14969          86 :     if (!dopt->dumpSchema)
   14970          12 :         return;
   14971             : 
   14972          74 :     q = createPQExpBuffer();
   14973          74 :     delq = createPQExpBuffer();
   14974             : 
   14975          74 :     qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
   14976             : 
   14977          74 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
   14978          74 :                       fmtQualifiedDumpable(prsinfo));
   14979             : 
   14980          74 :     appendPQExpBuffer(q, "    START = %s,\n",
   14981             :                       convertTSFunction(fout, prsinfo->prsstart));
   14982          74 :     appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
   14983             :                       convertTSFunction(fout, prsinfo->prstoken));
   14984          74 :     appendPQExpBuffer(q, "    END = %s,\n",
   14985             :                       convertTSFunction(fout, prsinfo->prsend));
   14986          74 :     if (prsinfo->prsheadline != InvalidOid)
   14987           6 :         appendPQExpBuffer(q, "    HEADLINE = %s,\n",
   14988             :                           convertTSFunction(fout, prsinfo->prsheadline));
   14989          74 :     appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
   14990             :                       convertTSFunction(fout, prsinfo->prslextype));
   14991             : 
   14992          74 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
   14993          74 :                       fmtQualifiedDumpable(prsinfo));
   14994             : 
   14995          74 :     if (dopt->binary_upgrade)
   14996           2 :         binary_upgrade_extension_member(q, &prsinfo->dobj,
   14997             :                                         "TEXT SEARCH PARSER", qprsname,
   14998           2 :                                         prsinfo->dobj.namespace->dobj.name);
   14999             : 
   15000          74 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15001          74 :         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
   15002          74 :                      ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
   15003             :                                   .namespace = prsinfo->dobj.namespace->dobj.name,
   15004             :                                   .description = "TEXT SEARCH PARSER",
   15005             :                                   .section = SECTION_PRE_DATA,
   15006             :                                   .createStmt = q->data,
   15007             :                                   .dropStmt = delq->data));
   15008             : 
   15009             :     /* Dump Parser Comments */
   15010          74 :     if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15011          74 :         dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
   15012          74 :                     prsinfo->dobj.namespace->dobj.name, "",
   15013             :                     prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
   15014             : 
   15015          74 :     destroyPQExpBuffer(q);
   15016          74 :     destroyPQExpBuffer(delq);
   15017          74 :     free(qprsname);
   15018             : }
   15019             : 
   15020             : /*
   15021             :  * dumpTSDictionary
   15022             :  *    write out a single text search dictionary
   15023             :  */
   15024             : static void
   15025         350 : dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
   15026             : {
   15027         350 :     DumpOptions *dopt = fout->dopt;
   15028             :     PQExpBuffer q;
   15029             :     PQExpBuffer delq;
   15030             :     PQExpBuffer query;
   15031             :     char       *qdictname;
   15032             :     PGresult   *res;
   15033             :     char       *nspname;
   15034             :     char       *tmplname;
   15035             : 
   15036             :     /* Do nothing if not dumping schema */
   15037         350 :     if (!dopt->dumpSchema)
   15038          12 :         return;
   15039             : 
   15040         338 :     q = createPQExpBuffer();
   15041         338 :     delq = createPQExpBuffer();
   15042         338 :     query = createPQExpBuffer();
   15043             : 
   15044         338 :     qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
   15045             : 
   15046             :     /* Fetch name and namespace of the dictionary's template */
   15047         338 :     appendPQExpBuffer(query, "SELECT nspname, tmplname "
   15048             :                       "FROM pg_ts_template p, pg_namespace n "
   15049             :                       "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
   15050             :                       dictinfo->dicttemplate);
   15051         338 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15052         338 :     nspname = PQgetvalue(res, 0, 0);
   15053         338 :     tmplname = PQgetvalue(res, 0, 1);
   15054             : 
   15055         338 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
   15056         338 :                       fmtQualifiedDumpable(dictinfo));
   15057             : 
   15058         338 :     appendPQExpBufferStr(q, "    TEMPLATE = ");
   15059         338 :     appendPQExpBuffer(q, "%s.", fmtId(nspname));
   15060         338 :     appendPQExpBufferStr(q, fmtId(tmplname));
   15061             : 
   15062         338 :     PQclear(res);
   15063             : 
   15064             :     /* the dictinitoption can be dumped straight into the command */
   15065         338 :     if (dictinfo->dictinitoption)
   15066         264 :         appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
   15067             : 
   15068         338 :     appendPQExpBufferStr(q, " );\n");
   15069             : 
   15070         338 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
   15071         338 :                       fmtQualifiedDumpable(dictinfo));
   15072             : 
   15073         338 :     if (dopt->binary_upgrade)
   15074          20 :         binary_upgrade_extension_member(q, &dictinfo->dobj,
   15075             :                                         "TEXT SEARCH DICTIONARY", qdictname,
   15076          20 :                                         dictinfo->dobj.namespace->dobj.name);
   15077             : 
   15078         338 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15079         338 :         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
   15080         338 :                      ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
   15081             :                                   .namespace = dictinfo->dobj.namespace->dobj.name,
   15082             :                                   .owner = dictinfo->rolname,
   15083             :                                   .description = "TEXT SEARCH DICTIONARY",
   15084             :                                   .section = SECTION_PRE_DATA,
   15085             :                                   .createStmt = q->data,
   15086             :                                   .dropStmt = delq->data));
   15087             : 
   15088             :     /* Dump Dictionary Comments */
   15089         338 :     if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15090         248 :         dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
   15091         248 :                     dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
   15092             :                     dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
   15093             : 
   15094         338 :     destroyPQExpBuffer(q);
   15095         338 :     destroyPQExpBuffer(delq);
   15096         338 :     destroyPQExpBuffer(query);
   15097         338 :     free(qdictname);
   15098             : }
   15099             : 
   15100             : /*
   15101             :  * dumpTSTemplate
   15102             :  *    write out a single text search template
   15103             :  */
   15104             : static void
   15105         110 : dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
   15106             : {
   15107         110 :     DumpOptions *dopt = fout->dopt;
   15108             :     PQExpBuffer q;
   15109             :     PQExpBuffer delq;
   15110             :     char       *qtmplname;
   15111             : 
   15112             :     /* Do nothing if not dumping schema */
   15113         110 :     if (!dopt->dumpSchema)
   15114          12 :         return;
   15115             : 
   15116          98 :     q = createPQExpBuffer();
   15117          98 :     delq = createPQExpBuffer();
   15118             : 
   15119          98 :     qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
   15120             : 
   15121          98 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
   15122          98 :                       fmtQualifiedDumpable(tmplinfo));
   15123             : 
   15124          98 :     if (tmplinfo->tmplinit != InvalidOid)
   15125          30 :         appendPQExpBuffer(q, "    INIT = %s,\n",
   15126             :                           convertTSFunction(fout, tmplinfo->tmplinit));
   15127          98 :     appendPQExpBuffer(q, "    LEXIZE = %s );\n",
   15128             :                       convertTSFunction(fout, tmplinfo->tmpllexize));
   15129             : 
   15130          98 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
   15131          98 :                       fmtQualifiedDumpable(tmplinfo));
   15132             : 
   15133          98 :     if (dopt->binary_upgrade)
   15134           2 :         binary_upgrade_extension_member(q, &tmplinfo->dobj,
   15135             :                                         "TEXT SEARCH TEMPLATE", qtmplname,
   15136           2 :                                         tmplinfo->dobj.namespace->dobj.name);
   15137             : 
   15138          98 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15139          98 :         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
   15140          98 :                      ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
   15141             :                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
   15142             :                                   .description = "TEXT SEARCH TEMPLATE",
   15143             :                                   .section = SECTION_PRE_DATA,
   15144             :                                   .createStmt = q->data,
   15145             :                                   .dropStmt = delq->data));
   15146             : 
   15147             :     /* Dump Template Comments */
   15148          98 :     if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15149          98 :         dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
   15150          98 :                     tmplinfo->dobj.namespace->dobj.name, "",
   15151             :                     tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
   15152             : 
   15153          98 :     destroyPQExpBuffer(q);
   15154          98 :     destroyPQExpBuffer(delq);
   15155          98 :     free(qtmplname);
   15156             : }
   15157             : 
   15158             : /*
   15159             :  * dumpTSConfig
   15160             :  *    write out a single text search configuration
   15161             :  */
   15162             : static void
   15163         300 : dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
   15164             : {
   15165         300 :     DumpOptions *dopt = fout->dopt;
   15166             :     PQExpBuffer q;
   15167             :     PQExpBuffer delq;
   15168             :     PQExpBuffer query;
   15169             :     char       *qcfgname;
   15170             :     PGresult   *res;
   15171             :     char       *nspname;
   15172             :     char       *prsname;
   15173             :     int         ntups,
   15174             :                 i;
   15175             :     int         i_tokenname;
   15176             :     int         i_dictname;
   15177             : 
   15178             :     /* Do nothing if not dumping schema */
   15179         300 :     if (!dopt->dumpSchema)
   15180          12 :         return;
   15181             : 
   15182         288 :     q = createPQExpBuffer();
   15183         288 :     delq = createPQExpBuffer();
   15184         288 :     query = createPQExpBuffer();
   15185             : 
   15186         288 :     qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
   15187             : 
   15188             :     /* Fetch name and namespace of the config's parser */
   15189         288 :     appendPQExpBuffer(query, "SELECT nspname, prsname "
   15190             :                       "FROM pg_ts_parser p, pg_namespace n "
   15191             :                       "WHERE p.oid = '%u' AND n.oid = prsnamespace",
   15192             :                       cfginfo->cfgparser);
   15193         288 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15194         288 :     nspname = PQgetvalue(res, 0, 0);
   15195         288 :     prsname = PQgetvalue(res, 0, 1);
   15196             : 
   15197         288 :     appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
   15198         288 :                       fmtQualifiedDumpable(cfginfo));
   15199             : 
   15200         288 :     appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
   15201         288 :     appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
   15202             : 
   15203         288 :     PQclear(res);
   15204             : 
   15205         288 :     resetPQExpBuffer(query);
   15206         288 :     appendPQExpBuffer(query,
   15207             :                       "SELECT\n"
   15208             :                       "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
   15209             :                       "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
   15210             :                       "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
   15211             :                       "FROM pg_catalog.pg_ts_config_map AS m\n"
   15212             :                       "WHERE m.mapcfg = '%u'\n"
   15213             :                       "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
   15214             :                       cfginfo->cfgparser, cfginfo->dobj.catId.oid);
   15215             : 
   15216         288 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15217         288 :     ntups = PQntuples(res);
   15218             : 
   15219         288 :     i_tokenname = PQfnumber(res, "tokenname");
   15220         288 :     i_dictname = PQfnumber(res, "dictname");
   15221             : 
   15222        6030 :     for (i = 0; i < ntups; i++)
   15223             :     {
   15224        5742 :         char       *tokenname = PQgetvalue(res, i, i_tokenname);
   15225        5742 :         char       *dictname = PQgetvalue(res, i, i_dictname);
   15226             : 
   15227        5742 :         if (i == 0 ||
   15228        5454 :             strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
   15229             :         {
   15230             :             /* starting a new token type, so start a new command */
   15231        5472 :             if (i > 0)
   15232        5184 :                 appendPQExpBufferStr(q, ";\n");
   15233        5472 :             appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
   15234        5472 :                               fmtQualifiedDumpable(cfginfo));
   15235             :             /* tokenname needs quoting, dictname does NOT */
   15236        5472 :             appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
   15237             :                               fmtId(tokenname), dictname);
   15238             :         }
   15239             :         else
   15240         270 :             appendPQExpBuffer(q, ", %s", dictname);
   15241             :     }
   15242             : 
   15243         288 :     if (ntups > 0)
   15244         288 :         appendPQExpBufferStr(q, ";\n");
   15245             : 
   15246         288 :     PQclear(res);
   15247             : 
   15248         288 :     appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
   15249         288 :                       fmtQualifiedDumpable(cfginfo));
   15250             : 
   15251         288 :     if (dopt->binary_upgrade)
   15252          10 :         binary_upgrade_extension_member(q, &cfginfo->dobj,
   15253             :                                         "TEXT SEARCH CONFIGURATION", qcfgname,
   15254          10 :                                         cfginfo->dobj.namespace->dobj.name);
   15255             : 
   15256         288 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15257         288 :         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
   15258         288 :                      ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
   15259             :                                   .namespace = cfginfo->dobj.namespace->dobj.name,
   15260             :                                   .owner = cfginfo->rolname,
   15261             :                                   .description = "TEXT SEARCH CONFIGURATION",
   15262             :                                   .section = SECTION_PRE_DATA,
   15263             :                                   .createStmt = q->data,
   15264             :                                   .dropStmt = delq->data));
   15265             : 
   15266             :     /* Dump Configuration Comments */
   15267         288 :     if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15268         248 :         dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
   15269         248 :                     cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
   15270             :                     cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
   15271             : 
   15272         288 :     destroyPQExpBuffer(q);
   15273         288 :     destroyPQExpBuffer(delq);
   15274         288 :     destroyPQExpBuffer(query);
   15275         288 :     free(qcfgname);
   15276             : }
   15277             : 
   15278             : /*
   15279             :  * dumpForeignDataWrapper
   15280             :  *    write out a single foreign-data wrapper definition
   15281             :  */
   15282             : static void
   15283         108 : dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
   15284             : {
   15285         108 :     DumpOptions *dopt = fout->dopt;
   15286             :     PQExpBuffer q;
   15287             :     PQExpBuffer delq;
   15288             :     char       *qfdwname;
   15289             : 
   15290             :     /* Do nothing if not dumping schema */
   15291         108 :     if (!dopt->dumpSchema)
   15292          14 :         return;
   15293             : 
   15294          94 :     q = createPQExpBuffer();
   15295          94 :     delq = createPQExpBuffer();
   15296             : 
   15297          94 :     qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
   15298             : 
   15299          94 :     appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
   15300             :                       qfdwname);
   15301             : 
   15302          94 :     if (strcmp(fdwinfo->fdwhandler, "-") != 0)
   15303           0 :         appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
   15304             : 
   15305          94 :     if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
   15306           0 :         appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
   15307             : 
   15308          94 :     if (strlen(fdwinfo->fdwoptions) > 0)
   15309           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
   15310             : 
   15311          94 :     appendPQExpBufferStr(q, ";\n");
   15312             : 
   15313          94 :     appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
   15314             :                       qfdwname);
   15315             : 
   15316          94 :     if (dopt->binary_upgrade)
   15317           4 :         binary_upgrade_extension_member(q, &fdwinfo->dobj,
   15318             :                                         "FOREIGN DATA WRAPPER", qfdwname,
   15319             :                                         NULL);
   15320             : 
   15321          94 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15322          94 :         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
   15323          94 :                      ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
   15324             :                                   .owner = fdwinfo->rolname,
   15325             :                                   .description = "FOREIGN DATA WRAPPER",
   15326             :                                   .section = SECTION_PRE_DATA,
   15327             :                                   .createStmt = q->data,
   15328             :                                   .dropStmt = delq->data));
   15329             : 
   15330             :     /* Dump Foreign Data Wrapper Comments */
   15331          94 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15332           0 :         dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
   15333             :                     NULL, fdwinfo->rolname,
   15334             :                     fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
   15335             : 
   15336             :     /* Handle the ACL */
   15337          94 :     if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15338          66 :         dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
   15339             :                 "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
   15340             :                 NULL, fdwinfo->rolname, &fdwinfo->dacl);
   15341             : 
   15342          94 :     free(qfdwname);
   15343             : 
   15344          94 :     destroyPQExpBuffer(q);
   15345          94 :     destroyPQExpBuffer(delq);
   15346             : }
   15347             : 
   15348             : /*
   15349             :  * dumpForeignServer
   15350             :  *    write out a foreign server definition
   15351             :  */
   15352             : static void
   15353         116 : dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
   15354             : {
   15355         116 :     DumpOptions *dopt = fout->dopt;
   15356             :     PQExpBuffer q;
   15357             :     PQExpBuffer delq;
   15358             :     PQExpBuffer query;
   15359             :     PGresult   *res;
   15360             :     char       *qsrvname;
   15361             :     char       *fdwname;
   15362             : 
   15363             :     /* Do nothing if not dumping schema */
   15364         116 :     if (!dopt->dumpSchema)
   15365          18 :         return;
   15366             : 
   15367          98 :     q = createPQExpBuffer();
   15368          98 :     delq = createPQExpBuffer();
   15369          98 :     query = createPQExpBuffer();
   15370             : 
   15371          98 :     qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
   15372             : 
   15373             :     /* look up the foreign-data wrapper */
   15374          98 :     appendPQExpBuffer(query, "SELECT fdwname "
   15375             :                       "FROM pg_foreign_data_wrapper w "
   15376             :                       "WHERE w.oid = '%u'",
   15377             :                       srvinfo->srvfdw);
   15378          98 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   15379          98 :     fdwname = PQgetvalue(res, 0, 0);
   15380             : 
   15381          98 :     appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
   15382          98 :     if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
   15383             :     {
   15384           0 :         appendPQExpBufferStr(q, " TYPE ");
   15385           0 :         appendStringLiteralAH(q, srvinfo->srvtype, fout);
   15386             :     }
   15387          98 :     if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
   15388             :     {
   15389           0 :         appendPQExpBufferStr(q, " VERSION ");
   15390           0 :         appendStringLiteralAH(q, srvinfo->srvversion, fout);
   15391             :     }
   15392             : 
   15393          98 :     appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
   15394          98 :     appendPQExpBufferStr(q, fmtId(fdwname));
   15395             : 
   15396          98 :     if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
   15397           0 :         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
   15398             : 
   15399          98 :     appendPQExpBufferStr(q, ";\n");
   15400             : 
   15401          98 :     appendPQExpBuffer(delq, "DROP SERVER %s;\n",
   15402             :                       qsrvname);
   15403             : 
   15404          98 :     if (dopt->binary_upgrade)
   15405           4 :         binary_upgrade_extension_member(q, &srvinfo->dobj,
   15406             :                                         "SERVER", qsrvname, NULL);
   15407             : 
   15408          98 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   15409          98 :         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
   15410          98 :                      ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
   15411             :                                   .owner = srvinfo->rolname,
   15412             :                                   .description = "SERVER",
   15413             :                                   .section = SECTION_PRE_DATA,
   15414             :                                   .createStmt = q->data,
   15415             :                                   .dropStmt = delq->data));
   15416             : 
   15417             :     /* Dump Foreign Server Comments */
   15418          98 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   15419           0 :         dumpComment(fout, "SERVER", qsrvname,
   15420             :                     NULL, srvinfo->rolname,
   15421             :                     srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
   15422             : 
   15423             :     /* Handle the ACL */
   15424          98 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15425          66 :         dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
   15426             :                 "FOREIGN SERVER", qsrvname, NULL, NULL,
   15427             :                 NULL, srvinfo->rolname, &srvinfo->dacl);
   15428             : 
   15429             :     /* Dump user mappings */
   15430          98 :     if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
   15431          98 :         dumpUserMappings(fout,
   15432          98 :                          srvinfo->dobj.name, NULL,
   15433             :                          srvinfo->rolname,
   15434             :                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
   15435             : 
   15436          98 :     PQclear(res);
   15437             : 
   15438          98 :     free(qsrvname);
   15439             : 
   15440          98 :     destroyPQExpBuffer(q);
   15441          98 :     destroyPQExpBuffer(delq);
   15442          98 :     destroyPQExpBuffer(query);
   15443             : }
   15444             : 
   15445             : /*
   15446             :  * dumpUserMappings
   15447             :  *
   15448             :  * This routine is used to dump any user mappings associated with the
   15449             :  * server handed to this routine. Should be called after ArchiveEntry()
   15450             :  * for the server.
   15451             :  */
   15452             : static void
   15453          98 : dumpUserMappings(Archive *fout,
   15454             :                  const char *servername, const char *namespace,
   15455             :                  const char *owner,
   15456             :                  CatalogId catalogId, DumpId dumpId)
   15457             : {
   15458             :     PQExpBuffer q;
   15459             :     PQExpBuffer delq;
   15460             :     PQExpBuffer query;
   15461             :     PQExpBuffer tag;
   15462             :     PGresult   *res;
   15463             :     int         ntups;
   15464             :     int         i_usename;
   15465             :     int         i_umoptions;
   15466             :     int         i;
   15467             : 
   15468          98 :     q = createPQExpBuffer();
   15469          98 :     tag = createPQExpBuffer();
   15470          98 :     delq = createPQExpBuffer();
   15471          98 :     query = createPQExpBuffer();
   15472             : 
   15473             :     /*
   15474             :      * We read from the publicly accessible view pg_user_mappings, so as not
   15475             :      * to fail if run by a non-superuser.  Note that the view will show
   15476             :      * umoptions as null if the user hasn't got privileges for the associated
   15477             :      * server; this means that pg_dump will dump such a mapping, but with no
   15478             :      * OPTIONS clause.  A possible alternative is to skip such mappings
   15479             :      * altogether, but it's not clear that that's an improvement.
   15480             :      */
   15481          98 :     appendPQExpBuffer(query,
   15482             :                       "SELECT usename, "
   15483             :                       "array_to_string(ARRAY("
   15484             :                       "SELECT quote_ident(option_name) || ' ' || "
   15485             :                       "quote_literal(option_value) "
   15486             :                       "FROM pg_options_to_table(umoptions) "
   15487             :                       "ORDER BY option_name"
   15488             :                       "), E',\n    ') AS umoptions "
   15489             :                       "FROM pg_user_mappings "
   15490             :                       "WHERE srvid = '%u' "
   15491             :                       "ORDER BY usename",
   15492             :                       catalogId.oid);
   15493             : 
   15494          98 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   15495             : 
   15496          98 :     ntups = PQntuples(res);
   15497          98 :     i_usename = PQfnumber(res, "usename");
   15498          98 :     i_umoptions = PQfnumber(res, "umoptions");
   15499             : 
   15500         164 :     for (i = 0; i < ntups; i++)
   15501             :     {
   15502             :         char       *usename;
   15503             :         char       *umoptions;
   15504             : 
   15505          66 :         usename = PQgetvalue(res, i, i_usename);
   15506          66 :         umoptions = PQgetvalue(res, i, i_umoptions);
   15507             : 
   15508          66 :         resetPQExpBuffer(q);
   15509          66 :         appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
   15510          66 :         appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
   15511             : 
   15512          66 :         if (umoptions && strlen(umoptions) > 0)
   15513           0 :             appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
   15514             : 
   15515          66 :         appendPQExpBufferStr(q, ";\n");
   15516             : 
   15517          66 :         resetPQExpBuffer(delq);
   15518          66 :         appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
   15519          66 :         appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
   15520             : 
   15521          66 :         resetPQExpBuffer(tag);
   15522          66 :         appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
   15523             :                           usename, servername);
   15524             : 
   15525          66 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15526          66 :                      ARCHIVE_OPTS(.tag = tag->data,
   15527             :                                   .namespace = namespace,
   15528             :                                   .owner = owner,
   15529             :                                   .description = "USER MAPPING",
   15530             :                                   .section = SECTION_PRE_DATA,
   15531             :                                   .createStmt = q->data,
   15532             :                                   .dropStmt = delq->data));
   15533             :     }
   15534             : 
   15535          98 :     PQclear(res);
   15536             : 
   15537          98 :     destroyPQExpBuffer(query);
   15538          98 :     destroyPQExpBuffer(delq);
   15539          98 :     destroyPQExpBuffer(tag);
   15540          98 :     destroyPQExpBuffer(q);
   15541          98 : }
   15542             : 
   15543             : /*
   15544             :  * Write out default privileges information
   15545             :  */
   15546             : static void
   15547         316 : dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
   15548             : {
   15549         316 :     DumpOptions *dopt = fout->dopt;
   15550             :     PQExpBuffer q;
   15551             :     PQExpBuffer tag;
   15552             :     const char *type;
   15553             : 
   15554             :     /* Do nothing if not dumping schema, or if we're skipping ACLs */
   15555         316 :     if (!dopt->dumpSchema || dopt->aclsSkip)
   15556          56 :         return;
   15557             : 
   15558         260 :     q = createPQExpBuffer();
   15559         260 :     tag = createPQExpBuffer();
   15560             : 
   15561         260 :     switch (daclinfo->defaclobjtype)
   15562             :     {
   15563         130 :         case DEFACLOBJ_RELATION:
   15564         130 :             type = "TABLES";
   15565         130 :             break;
   15566           0 :         case DEFACLOBJ_SEQUENCE:
   15567           0 :             type = "SEQUENCES";
   15568           0 :             break;
   15569         130 :         case DEFACLOBJ_FUNCTION:
   15570         130 :             type = "FUNCTIONS";
   15571         130 :             break;
   15572           0 :         case DEFACLOBJ_TYPE:
   15573           0 :             type = "TYPES";
   15574           0 :             break;
   15575           0 :         case DEFACLOBJ_NAMESPACE:
   15576           0 :             type = "SCHEMAS";
   15577           0 :             break;
   15578           0 :         default:
   15579             :             /* shouldn't get here */
   15580           0 :             pg_fatal("unrecognized object type in default privileges: %d",
   15581             :                      (int) daclinfo->defaclobjtype);
   15582             :             type = "";            /* keep compiler quiet */
   15583             :     }
   15584             : 
   15585         260 :     appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
   15586             : 
   15587             :     /* build the actual command(s) for this tuple */
   15588         260 :     if (!buildDefaultACLCommands(type,
   15589         260 :                                  daclinfo->dobj.namespace != NULL ?
   15590         132 :                                  daclinfo->dobj.namespace->dobj.name : NULL,
   15591         260 :                                  daclinfo->dacl.acl,
   15592         260 :                                  daclinfo->dacl.acldefault,
   15593             :                                  daclinfo->defaclrole,
   15594             :                                  fout->remoteVersion,
   15595             :                                  q))
   15596           0 :         pg_fatal("could not parse default ACL list (%s)",
   15597             :                  daclinfo->dacl.acl);
   15598             : 
   15599         260 :     if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
   15600         260 :         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
   15601         260 :                      ARCHIVE_OPTS(.tag = tag->data,
   15602             :                                   .namespace = daclinfo->dobj.namespace ?
   15603             :                                   daclinfo->dobj.namespace->dobj.name : NULL,
   15604             :                                   .owner = daclinfo->defaclrole,
   15605             :                                   .description = "DEFAULT ACL",
   15606             :                                   .section = SECTION_POST_DATA,
   15607             :                                   .createStmt = q->data));
   15608             : 
   15609         260 :     destroyPQExpBuffer(tag);
   15610         260 :     destroyPQExpBuffer(q);
   15611             : }
   15612             : 
   15613             : /*----------
   15614             :  * Write out grant/revoke information
   15615             :  *
   15616             :  * 'objDumpId' is the dump ID of the underlying object.
   15617             :  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
   15618             :  *      or InvalidDumpId if there is no need for a second dependency.
   15619             :  * 'type' must be one of
   15620             :  *      TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
   15621             :  *      FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
   15622             :  * 'name' is the formatted name of the object.  Must be quoted etc. already.
   15623             :  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
   15624             :  *      (Currently we assume that subname is only provided for table columns.)
   15625             :  * 'nspname' is the namespace the object is in (NULL if none).
   15626             :  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
   15627             :  *      to use the default for the object type.
   15628             :  * 'owner' is the owner, NULL if there is no owner (for languages).
   15629             :  * 'dacl' is the DumpableAcl struct for the object.
   15630             :  *
   15631             :  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
   15632             :  * no ACL entry was created.
   15633             :  *----------
   15634             :  */
   15635             : static DumpId
   15636       46918 : dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
   15637             :         const char *type, const char *name, const char *subname,
   15638             :         const char *nspname, const char *tag, const char *owner,
   15639             :         const DumpableAcl *dacl)
   15640             : {
   15641       46918 :     DumpId      aclDumpId = InvalidDumpId;
   15642       46918 :     DumpOptions *dopt = fout->dopt;
   15643       46918 :     const char *acls = dacl->acl;
   15644       46918 :     const char *acldefault = dacl->acldefault;
   15645       46918 :     char        privtype = dacl->privtype;
   15646       46918 :     const char *initprivs = dacl->initprivs;
   15647             :     const char *baseacls;
   15648             :     PQExpBuffer sql;
   15649             : 
   15650             :     /* Do nothing if ACL dump is not enabled */
   15651       46918 :     if (dopt->aclsSkip)
   15652         636 :         return InvalidDumpId;
   15653             : 
   15654             :     /* --data-only skips ACLs *except* large object ACLs */
   15655       46282 :     if (!dopt->dumpSchema && strcmp(type, "LARGE OBJECT") != 0)
   15656           0 :         return InvalidDumpId;
   15657             : 
   15658       46282 :     sql = createPQExpBuffer();
   15659             : 
   15660             :     /*
   15661             :      * In binary upgrade mode, we don't run an extension's script but instead
   15662             :      * dump out the objects independently and then recreate them.  To preserve
   15663             :      * any initial privileges which were set on extension objects, we need to
   15664             :      * compute the set of GRANT and REVOKE commands necessary to get from the
   15665             :      * default privileges of an object to its initial privileges as recorded
   15666             :      * in pg_init_privs.
   15667             :      *
   15668             :      * At restore time, we apply these commands after having called
   15669             :      * binary_upgrade_set_record_init_privs(true).  That tells the backend to
   15670             :      * copy the results into pg_init_privs.  This is how we preserve the
   15671             :      * contents of that catalog across binary upgrades.
   15672             :      */
   15673       46282 :     if (dopt->binary_upgrade && privtype == 'e' &&
   15674          26 :         initprivs && *initprivs != '\0')
   15675             :     {
   15676          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
   15677          26 :         if (!buildACLCommands(name, subname, nspname, type,
   15678             :                               initprivs, acldefault, owner,
   15679             :                               "", fout->remoteVersion, sql))
   15680           0 :             pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15681             :                      initprivs, acldefault, name, type);
   15682          26 :         appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
   15683             :     }
   15684             : 
   15685             :     /*
   15686             :      * Now figure the GRANT and REVOKE commands needed to get to the object's
   15687             :      * actual current ACL, starting from the initprivs if given, else from the
   15688             :      * object-type-specific default.  Also, while buildACLCommands will assume
   15689             :      * that a NULL/empty acls string means it needn't do anything, what that
   15690             :      * actually represents is the object-type-specific default; so we need to
   15691             :      * substitute the acldefault string to get the right results in that case.
   15692             :      */
   15693       46282 :     if (initprivs && *initprivs != '\0')
   15694             :     {
   15695       42678 :         baseacls = initprivs;
   15696       42678 :         if (acls == NULL || *acls == '\0')
   15697          34 :             acls = acldefault;
   15698             :     }
   15699             :     else
   15700        3604 :         baseacls = acldefault;
   15701             : 
   15702       46282 :     if (!buildACLCommands(name, subname, nspname, type,
   15703             :                           acls, baseacls, owner,
   15704             :                           "", fout->remoteVersion, sql))
   15705           0 :         pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
   15706             :                  acls, baseacls, name, type);
   15707             : 
   15708       46282 :     if (sql->len > 0)
   15709             :     {
   15710        3764 :         PQExpBuffer tagbuf = createPQExpBuffer();
   15711             :         DumpId      aclDeps[2];
   15712        3764 :         int         nDeps = 0;
   15713             : 
   15714        3764 :         if (tag)
   15715           0 :             appendPQExpBufferStr(tagbuf, tag);
   15716        3764 :         else if (subname)
   15717        2222 :             appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
   15718             :         else
   15719        1542 :             appendPQExpBuffer(tagbuf, "%s %s", type, name);
   15720             : 
   15721        3764 :         aclDeps[nDeps++] = objDumpId;
   15722        3764 :         if (altDumpId != InvalidDumpId)
   15723        2050 :             aclDeps[nDeps++] = altDumpId;
   15724             : 
   15725        3764 :         aclDumpId = createDumpId();
   15726             : 
   15727        3764 :         ArchiveEntry(fout, nilCatalogId, aclDumpId,
   15728        3764 :                      ARCHIVE_OPTS(.tag = tagbuf->data,
   15729             :                                   .namespace = nspname,
   15730             :                                   .owner = owner,
   15731             :                                   .description = "ACL",
   15732             :                                   .section = SECTION_NONE,
   15733             :                                   .createStmt = sql->data,
   15734             :                                   .deps = aclDeps,
   15735             :                                   .nDeps = nDeps));
   15736             : 
   15737        3764 :         destroyPQExpBuffer(tagbuf);
   15738             :     }
   15739             : 
   15740       46282 :     destroyPQExpBuffer(sql);
   15741             : 
   15742       46282 :     return aclDumpId;
   15743             : }
   15744             : 
   15745             : /*
   15746             :  * dumpSecLabel
   15747             :  *
   15748             :  * This routine is used to dump any security labels associated with the
   15749             :  * object handed to this routine. The routine takes the object type
   15750             :  * and object name (ready to print, except for schema decoration), plus
   15751             :  * the namespace and owner of the object (for labeling the ArchiveEntry),
   15752             :  * plus catalog ID and subid which are the lookup key for pg_seclabel,
   15753             :  * plus the dump ID for the object (for setting a dependency).
   15754             :  * If a matching pg_seclabel entry is found, it is dumped.
   15755             :  *
   15756             :  * Note: although this routine takes a dumpId for dependency purposes,
   15757             :  * that purpose is just to mark the dependency in the emitted dump file
   15758             :  * for possible future use by pg_restore.  We do NOT use it for determining
   15759             :  * ordering of the label in the dump file, because this routine is called
   15760             :  * after dependency sorting occurs.  This routine should be called just after
   15761             :  * calling ArchiveEntry() for the specified object.
   15762             :  */
   15763             : static void
   15764           0 : dumpSecLabel(Archive *fout, const char *type, const char *name,
   15765             :              const char *namespace, const char *owner,
   15766             :              CatalogId catalogId, int subid, DumpId dumpId)
   15767             : {
   15768           0 :     DumpOptions *dopt = fout->dopt;
   15769             :     SecLabelItem *labels;
   15770             :     int         nlabels;
   15771             :     int         i;
   15772             :     PQExpBuffer query;
   15773             : 
   15774             :     /* do nothing, if --no-security-labels is supplied */
   15775           0 :     if (dopt->no_security_labels)
   15776           0 :         return;
   15777             : 
   15778             :     /*
   15779             :      * Security labels are schema not data ... except large object labels are
   15780             :      * data
   15781             :      */
   15782           0 :     if (strcmp(type, "LARGE OBJECT") != 0)
   15783             :     {
   15784           0 :         if (!dopt->dumpSchema)
   15785           0 :             return;
   15786             :     }
   15787             :     else
   15788             :     {
   15789             :         /* We do dump large object security labels in binary-upgrade mode */
   15790           0 :         if (!dopt->dumpData && !dopt->binary_upgrade)
   15791           0 :             return;
   15792             :     }
   15793             : 
   15794             :     /* Search for security labels associated with catalogId, using table */
   15795           0 :     nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
   15796             : 
   15797           0 :     query = createPQExpBuffer();
   15798             : 
   15799           0 :     for (i = 0; i < nlabels; i++)
   15800             :     {
   15801             :         /*
   15802             :          * Ignore label entries for which the subid doesn't match.
   15803             :          */
   15804           0 :         if (labels[i].objsubid != subid)
   15805           0 :             continue;
   15806             : 
   15807           0 :         appendPQExpBuffer(query,
   15808             :                           "SECURITY LABEL FOR %s ON %s ",
   15809           0 :                           fmtId(labels[i].provider), type);
   15810           0 :         if (namespace && *namespace)
   15811           0 :             appendPQExpBuffer(query, "%s.", fmtId(namespace));
   15812           0 :         appendPQExpBuffer(query, "%s IS ", name);
   15813           0 :         appendStringLiteralAH(query, labels[i].label, fout);
   15814           0 :         appendPQExpBufferStr(query, ";\n");
   15815             :     }
   15816             : 
   15817           0 :     if (query->len > 0)
   15818             :     {
   15819           0 :         PQExpBuffer tag = createPQExpBuffer();
   15820             : 
   15821           0 :         appendPQExpBuffer(tag, "%s %s", type, name);
   15822           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15823           0 :                      ARCHIVE_OPTS(.tag = tag->data,
   15824             :                                   .namespace = namespace,
   15825             :                                   .owner = owner,
   15826             :                                   .description = "SECURITY LABEL",
   15827             :                                   .section = SECTION_NONE,
   15828             :                                   .createStmt = query->data,
   15829             :                                   .deps = &dumpId,
   15830             :                                   .nDeps = 1));
   15831           0 :         destroyPQExpBuffer(tag);
   15832             :     }
   15833             : 
   15834           0 :     destroyPQExpBuffer(query);
   15835             : }
   15836             : 
   15837             : /*
   15838             :  * dumpTableSecLabel
   15839             :  *
   15840             :  * As above, but dump security label for both the specified table (or view)
   15841             :  * and its columns.
   15842             :  */
   15843             : static void
   15844           0 : dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
   15845             : {
   15846           0 :     DumpOptions *dopt = fout->dopt;
   15847             :     SecLabelItem *labels;
   15848             :     int         nlabels;
   15849             :     int         i;
   15850             :     PQExpBuffer query;
   15851             :     PQExpBuffer target;
   15852             : 
   15853             :     /* do nothing, if --no-security-labels is supplied */
   15854           0 :     if (dopt->no_security_labels)
   15855           0 :         return;
   15856             : 
   15857             :     /* SecLabel are SCHEMA not data */
   15858           0 :     if (!dopt->dumpSchema)
   15859           0 :         return;
   15860             : 
   15861             :     /* Search for comments associated with relation, using table */
   15862           0 :     nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
   15863             :                             tbinfo->dobj.catId.oid,
   15864             :                             &labels);
   15865             : 
   15866             :     /* If security labels exist, build SECURITY LABEL statements */
   15867           0 :     if (nlabels <= 0)
   15868           0 :         return;
   15869             : 
   15870           0 :     query = createPQExpBuffer();
   15871           0 :     target = createPQExpBuffer();
   15872             : 
   15873           0 :     for (i = 0; i < nlabels; i++)
   15874             :     {
   15875             :         const char *colname;
   15876           0 :         const char *provider = labels[i].provider;
   15877           0 :         const char *label = labels[i].label;
   15878           0 :         int         objsubid = labels[i].objsubid;
   15879             : 
   15880           0 :         resetPQExpBuffer(target);
   15881           0 :         if (objsubid == 0)
   15882             :         {
   15883           0 :             appendPQExpBuffer(target, "%s %s", reltypename,
   15884           0 :                               fmtQualifiedDumpable(tbinfo));
   15885             :         }
   15886             :         else
   15887             :         {
   15888           0 :             colname = getAttrName(objsubid, tbinfo);
   15889             :             /* first fmtXXX result must be consumed before calling again */
   15890           0 :             appendPQExpBuffer(target, "COLUMN %s",
   15891           0 :                               fmtQualifiedDumpable(tbinfo));
   15892           0 :             appendPQExpBuffer(target, ".%s", fmtId(colname));
   15893             :         }
   15894           0 :         appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
   15895             :                           fmtId(provider), target->data);
   15896           0 :         appendStringLiteralAH(query, label, fout);
   15897           0 :         appendPQExpBufferStr(query, ";\n");
   15898             :     }
   15899           0 :     if (query->len > 0)
   15900             :     {
   15901           0 :         resetPQExpBuffer(target);
   15902           0 :         appendPQExpBuffer(target, "%s %s", reltypename,
   15903           0 :                           fmtId(tbinfo->dobj.name));
   15904           0 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   15905           0 :                      ARCHIVE_OPTS(.tag = target->data,
   15906             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   15907             :                                   .owner = tbinfo->rolname,
   15908             :                                   .description = "SECURITY LABEL",
   15909             :                                   .section = SECTION_NONE,
   15910             :                                   .createStmt = query->data,
   15911             :                                   .deps = &(tbinfo->dobj.dumpId),
   15912             :                                   .nDeps = 1));
   15913             :     }
   15914           0 :     destroyPQExpBuffer(query);
   15915           0 :     destroyPQExpBuffer(target);
   15916             : }
   15917             : 
   15918             : /*
   15919             :  * findSecLabels
   15920             :  *
   15921             :  * Find the security label(s), if any, associated with the given object.
   15922             :  * All the objsubid values associated with the given classoid/objoid are
   15923             :  * found with one search.
   15924             :  */
   15925             : static int
   15926           0 : findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
   15927             : {
   15928           0 :     SecLabelItem *middle = NULL;
   15929             :     SecLabelItem *low;
   15930             :     SecLabelItem *high;
   15931             :     int         nmatch;
   15932             : 
   15933           0 :     if (nseclabels <= 0)     /* no labels, so no match is possible */
   15934             :     {
   15935           0 :         *items = NULL;
   15936           0 :         return 0;
   15937             :     }
   15938             : 
   15939             :     /*
   15940             :      * Do binary search to find some item matching the object.
   15941             :      */
   15942           0 :     low = &seclabels[0];
   15943           0 :     high = &seclabels[nseclabels - 1];
   15944           0 :     while (low <= high)
   15945             :     {
   15946           0 :         middle = low + (high - low) / 2;
   15947             : 
   15948           0 :         if (classoid < middle->classoid)
   15949           0 :             high = middle - 1;
   15950           0 :         else if (classoid > middle->classoid)
   15951           0 :             low = middle + 1;
   15952           0 :         else if (objoid < middle->objoid)
   15953           0 :             high = middle - 1;
   15954           0 :         else if (objoid > middle->objoid)
   15955           0 :             low = middle + 1;
   15956             :         else
   15957           0 :             break;              /* found a match */
   15958             :     }
   15959             : 
   15960           0 :     if (low > high)              /* no matches */
   15961             :     {
   15962           0 :         *items = NULL;
   15963           0 :         return 0;
   15964             :     }
   15965             : 
   15966             :     /*
   15967             :      * Now determine how many items match the object.  The search loop
   15968             :      * invariant still holds: only items between low and high inclusive could
   15969             :      * match.
   15970             :      */
   15971           0 :     nmatch = 1;
   15972           0 :     while (middle > low)
   15973             :     {
   15974           0 :         if (classoid != middle[-1].classoid ||
   15975           0 :             objoid != middle[-1].objoid)
   15976             :             break;
   15977           0 :         middle--;
   15978           0 :         nmatch++;
   15979             :     }
   15980             : 
   15981           0 :     *items = middle;
   15982             : 
   15983           0 :     middle += nmatch;
   15984           0 :     while (middle <= high)
   15985             :     {
   15986           0 :         if (classoid != middle->classoid ||
   15987           0 :             objoid != middle->objoid)
   15988             :             break;
   15989           0 :         middle++;
   15990           0 :         nmatch++;
   15991             :     }
   15992             : 
   15993           0 :     return nmatch;
   15994             : }
   15995             : 
   15996             : /*
   15997             :  * collectSecLabels
   15998             :  *
   15999             :  * Construct a table of all security labels available for database objects;
   16000             :  * also set the has-seclabel component flag for each relevant object.
   16001             :  *
   16002             :  * The table is sorted by classoid/objid/objsubid for speed in lookup.
   16003             :  */
   16004             : static void
   16005         320 : collectSecLabels(Archive *fout)
   16006             : {
   16007             :     PGresult   *res;
   16008             :     PQExpBuffer query;
   16009             :     int         i_label;
   16010             :     int         i_provider;
   16011             :     int         i_classoid;
   16012             :     int         i_objoid;
   16013             :     int         i_objsubid;
   16014             :     int         ntups;
   16015             :     int         i;
   16016             :     DumpableObject *dobj;
   16017             : 
   16018         320 :     query = createPQExpBuffer();
   16019             : 
   16020         320 :     appendPQExpBufferStr(query,
   16021             :                          "SELECT label, provider, classoid, objoid, objsubid "
   16022             :                          "FROM pg_catalog.pg_seclabel "
   16023             :                          "ORDER BY classoid, objoid, objsubid");
   16024             : 
   16025         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16026             : 
   16027             :     /* Construct lookup table containing OIDs in numeric form */
   16028         320 :     i_label = PQfnumber(res, "label");
   16029         320 :     i_provider = PQfnumber(res, "provider");
   16030         320 :     i_classoid = PQfnumber(res, "classoid");
   16031         320 :     i_objoid = PQfnumber(res, "objoid");
   16032         320 :     i_objsubid = PQfnumber(res, "objsubid");
   16033             : 
   16034         320 :     ntups = PQntuples(res);
   16035             : 
   16036         320 :     seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
   16037         320 :     nseclabels = 0;
   16038         320 :     dobj = NULL;
   16039             : 
   16040         320 :     for (i = 0; i < ntups; i++)
   16041             :     {
   16042             :         CatalogId   objId;
   16043             :         int         subid;
   16044             : 
   16045           0 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
   16046           0 :         objId.oid = atooid(PQgetvalue(res, i, i_objoid));
   16047           0 :         subid = atoi(PQgetvalue(res, i, i_objsubid));
   16048             : 
   16049             :         /* We needn't remember labels that don't match any dumpable object */
   16050           0 :         if (dobj == NULL ||
   16051           0 :             dobj->catId.tableoid != objId.tableoid ||
   16052           0 :             dobj->catId.oid != objId.oid)
   16053           0 :             dobj = findObjectByCatalogId(objId);
   16054           0 :         if (dobj == NULL)
   16055           0 :             continue;
   16056             : 
   16057             :         /*
   16058             :          * Labels on columns of composite types are linked to the type's
   16059             :          * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
   16060             :          * in the type's own DumpableObject.
   16061             :          */
   16062           0 :         if (subid != 0 && dobj->objType == DO_TABLE &&
   16063           0 :             ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
   16064           0 :         {
   16065             :             TypeInfo   *cTypeInfo;
   16066             : 
   16067           0 :             cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
   16068           0 :             if (cTypeInfo)
   16069           0 :                 cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
   16070             :         }
   16071             :         else
   16072           0 :             dobj->components |= DUMP_COMPONENT_SECLABEL;
   16073             : 
   16074           0 :         seclabels[nseclabels].label = pg_strdup(PQgetvalue(res, i, i_label));
   16075           0 :         seclabels[nseclabels].provider = pg_strdup(PQgetvalue(res, i, i_provider));
   16076           0 :         seclabels[nseclabels].classoid = objId.tableoid;
   16077           0 :         seclabels[nseclabels].objoid = objId.oid;
   16078           0 :         seclabels[nseclabels].objsubid = subid;
   16079           0 :         nseclabels++;
   16080             :     }
   16081             : 
   16082         320 :     PQclear(res);
   16083         320 :     destroyPQExpBuffer(query);
   16084         320 : }
   16085             : 
   16086             : /*
   16087             :  * dumpTable
   16088             :  *    write out to fout the declarations (not data) of a user-defined table
   16089             :  */
   16090             : static void
   16091       52734 : dumpTable(Archive *fout, const TableInfo *tbinfo)
   16092             : {
   16093       52734 :     DumpOptions *dopt = fout->dopt;
   16094       52734 :     DumpId      tableAclDumpId = InvalidDumpId;
   16095             :     char       *namecopy;
   16096             : 
   16097             :     /* Do nothing if not dumping schema */
   16098       52734 :     if (!dopt->dumpSchema)
   16099        2892 :         return;
   16100             : 
   16101       49842 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   16102             :     {
   16103       12616 :         if (tbinfo->relkind == RELKIND_SEQUENCE)
   16104         752 :             dumpSequence(fout, tbinfo);
   16105             :         else
   16106       11864 :             dumpTableSchema(fout, tbinfo);
   16107             :     }
   16108             : 
   16109             :     /* Handle the ACL here */
   16110       49842 :     namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
   16111       49842 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
   16112             :     {
   16113       38672 :         const char *objtype =
   16114       38672 :             (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
   16115             : 
   16116             :         tableAclDumpId =
   16117       38672 :             dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
   16118             :                     objtype, namecopy, NULL,
   16119       38672 :                     tbinfo->dobj.namespace->dobj.name,
   16120             :                     NULL, tbinfo->rolname, &tbinfo->dacl);
   16121             :     }
   16122             : 
   16123             :     /*
   16124             :      * Handle column ACLs, if any.  Note: we pull these with a separate query
   16125             :      * rather than trying to fetch them during getTableAttrs, so that we won't
   16126             :      * miss ACLs on system columns.  Doing it this way also allows us to dump
   16127             :      * ACLs for catalogs that we didn't mark "interesting" back in getTables.
   16128             :      */
   16129       49842 :     if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
   16130             :     {
   16131         522 :         PQExpBuffer query = createPQExpBuffer();
   16132             :         PGresult   *res;
   16133             :         int         i;
   16134             : 
   16135         522 :         if (!fout->is_prepared[PREPQUERY_GETCOLUMNACLS])
   16136             :         {
   16137             :             /* Set up query for column ACLs */
   16138         268 :             appendPQExpBufferStr(query,
   16139             :                                  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
   16140             : 
   16141         268 :             if (fout->remoteVersion >= 90600)
   16142             :             {
   16143             :                 /*
   16144             :                  * In principle we should call acldefault('c', relowner) to
   16145             :                  * get the default ACL for a column.  However, we don't
   16146             :                  * currently store the numeric OID of the relowner in
   16147             :                  * TableInfo.  We could convert the owner name using regrole,
   16148             :                  * but that creates a risk of failure due to concurrent role
   16149             :                  * renames.  Given that the default ACL for columns is empty
   16150             :                  * and is likely to stay that way, it's not worth extra cycles
   16151             :                  * and risk to avoid hard-wiring that knowledge here.
   16152             :                  */
   16153         268 :                 appendPQExpBufferStr(query,
   16154             :                                      "SELECT at.attname, "
   16155             :                                      "at.attacl, "
   16156             :                                      "'{}' AS acldefault, "
   16157             :                                      "pip.privtype, pip.initprivs "
   16158             :                                      "FROM pg_catalog.pg_attribute at "
   16159             :                                      "LEFT JOIN pg_catalog.pg_init_privs pip ON "
   16160             :                                      "(at.attrelid = pip.objoid "
   16161             :                                      "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
   16162             :                                      "AND at.attnum = pip.objsubid) "
   16163             :                                      "WHERE at.attrelid = $1 AND "
   16164             :                                      "NOT at.attisdropped "
   16165             :                                      "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
   16166             :                                      "ORDER BY at.attnum");
   16167             :             }
   16168             :             else
   16169             :             {
   16170           0 :                 appendPQExpBufferStr(query,
   16171             :                                      "SELECT attname, attacl, '{}' AS acldefault, "
   16172             :                                      "NULL AS privtype, NULL AS initprivs "
   16173             :                                      "FROM pg_catalog.pg_attribute "
   16174             :                                      "WHERE attrelid = $1 AND NOT attisdropped "
   16175             :                                      "AND attacl IS NOT NULL "
   16176             :                                      "ORDER BY attnum");
   16177             :             }
   16178             : 
   16179         268 :             ExecuteSqlStatement(fout, query->data);
   16180             : 
   16181         268 :             fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
   16182             :         }
   16183             : 
   16184         522 :         printfPQExpBuffer(query,
   16185             :                           "EXECUTE getColumnACLs('%u')",
   16186             :                           tbinfo->dobj.catId.oid);
   16187             : 
   16188         522 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16189             : 
   16190        7198 :         for (i = 0; i < PQntuples(res); i++)
   16191             :         {
   16192        6676 :             char       *attname = PQgetvalue(res, i, 0);
   16193        6676 :             char       *attacl = PQgetvalue(res, i, 1);
   16194        6676 :             char       *acldefault = PQgetvalue(res, i, 2);
   16195        6676 :             char        privtype = *(PQgetvalue(res, i, 3));
   16196        6676 :             char       *initprivs = PQgetvalue(res, i, 4);
   16197             :             DumpableAcl coldacl;
   16198             :             char       *attnamecopy;
   16199             : 
   16200        6676 :             coldacl.acl = attacl;
   16201        6676 :             coldacl.acldefault = acldefault;
   16202        6676 :             coldacl.privtype = privtype;
   16203        6676 :             coldacl.initprivs = initprivs;
   16204        6676 :             attnamecopy = pg_strdup(fmtId(attname));
   16205             : 
   16206             :             /*
   16207             :              * Column's GRANT type is always TABLE.  Each column ACL depends
   16208             :              * on the table-level ACL, since we can restore column ACLs in
   16209             :              * parallel but the table-level ACL has to be done first.
   16210             :              */
   16211        6676 :             dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
   16212             :                     "TABLE", namecopy, attnamecopy,
   16213        6676 :                     tbinfo->dobj.namespace->dobj.name,
   16214             :                     NULL, tbinfo->rolname, &coldacl);
   16215        6676 :             free(attnamecopy);
   16216             :         }
   16217         522 :         PQclear(res);
   16218         522 :         destroyPQExpBuffer(query);
   16219             :     }
   16220             : 
   16221       49842 :     free(namecopy);
   16222             : }
   16223             : 
   16224             : /*
   16225             :  * Create the AS clause for a view or materialized view. The semicolon is
   16226             :  * stripped because a materialized view must add a WITH NO DATA clause.
   16227             :  *
   16228             :  * This returns a new buffer which must be freed by the caller.
   16229             :  */
   16230             : static PQExpBuffer
   16231        1796 : createViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16232             : {
   16233        1796 :     PQExpBuffer query = createPQExpBuffer();
   16234        1796 :     PQExpBuffer result = createPQExpBuffer();
   16235             :     PGresult   *res;
   16236             :     int         len;
   16237             : 
   16238             :     /* Fetch the view definition */
   16239        1796 :     appendPQExpBuffer(query,
   16240             :                       "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
   16241             :                       tbinfo->dobj.catId.oid);
   16242             : 
   16243        1796 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   16244             : 
   16245        1796 :     if (PQntuples(res) != 1)
   16246             :     {
   16247           0 :         if (PQntuples(res) < 1)
   16248           0 :             pg_fatal("query to obtain definition of view \"%s\" returned no data",
   16249             :                      tbinfo->dobj.name);
   16250             :         else
   16251           0 :             pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
   16252             :                      tbinfo->dobj.name);
   16253             :     }
   16254             : 
   16255        1796 :     len = PQgetlength(res, 0, 0);
   16256             : 
   16257        1796 :     if (len == 0)
   16258           0 :         pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
   16259             :                  tbinfo->dobj.name);
   16260             : 
   16261             :     /* Strip off the trailing semicolon so that other things may follow. */
   16262             :     Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
   16263        1796 :     appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
   16264             : 
   16265        1796 :     PQclear(res);
   16266        1796 :     destroyPQExpBuffer(query);
   16267             : 
   16268        1796 :     return result;
   16269             : }
   16270             : 
   16271             : /*
   16272             :  * Create a dummy AS clause for a view.  This is used when the real view
   16273             :  * definition has to be postponed because of circular dependencies.
   16274             :  * We must duplicate the view's external properties -- column names and types
   16275             :  * (including collation) -- so that it works for subsequent references.
   16276             :  *
   16277             :  * This returns a new buffer which must be freed by the caller.
   16278             :  */
   16279             : static PQExpBuffer
   16280          40 : createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
   16281             : {
   16282          40 :     PQExpBuffer result = createPQExpBuffer();
   16283             :     int         j;
   16284             : 
   16285          40 :     appendPQExpBufferStr(result, "SELECT");
   16286             : 
   16287          80 :     for (j = 0; j < tbinfo->numatts; j++)
   16288             :     {
   16289          40 :         if (j > 0)
   16290          20 :             appendPQExpBufferChar(result, ',');
   16291          40 :         appendPQExpBufferStr(result, "\n    ");
   16292             : 
   16293          40 :         appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
   16294             : 
   16295             :         /*
   16296             :          * Must add collation if not default for the type, because CREATE OR
   16297             :          * REPLACE VIEW won't change it
   16298             :          */
   16299          40 :         if (OidIsValid(tbinfo->attcollation[j]))
   16300             :         {
   16301             :             CollInfo   *coll;
   16302             : 
   16303           0 :             coll = findCollationByOid(tbinfo->attcollation[j]);
   16304           0 :             if (coll)
   16305           0 :                 appendPQExpBuffer(result, " COLLATE %s",
   16306           0 :                                   fmtQualifiedDumpable(coll));
   16307             :         }
   16308             : 
   16309          40 :         appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
   16310             :     }
   16311             : 
   16312          40 :     return result;
   16313             : }
   16314             : 
   16315             : /*
   16316             :  * dumpTableSchema
   16317             :  *    write the declaration (not data) of one user-defined table or view
   16318             :  */
   16319             : static void
   16320       11864 : dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
   16321             : {
   16322       11864 :     DumpOptions *dopt = fout->dopt;
   16323       11864 :     PQExpBuffer q = createPQExpBuffer();
   16324       11864 :     PQExpBuffer delq = createPQExpBuffer();
   16325       11864 :     PQExpBuffer extra = createPQExpBuffer();
   16326             :     char       *qrelname;
   16327             :     char       *qualrelname;
   16328             :     int         numParents;
   16329             :     TableInfo **parents;
   16330             :     int         actual_atts;    /* number of attrs in this CREATE statement */
   16331             :     const char *reltypename;
   16332             :     char       *storage;
   16333             :     int         j,
   16334             :                 k;
   16335             : 
   16336             :     /* We had better have loaded per-column details about this table */
   16337             :     Assert(tbinfo->interesting);
   16338             : 
   16339       11864 :     qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
   16340       11864 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   16341             : 
   16342       11864 :     if (tbinfo->hasoids)
   16343           0 :         pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
   16344             :                        qrelname);
   16345             : 
   16346       11864 :     if (dopt->binary_upgrade)
   16347        1620 :         binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
   16348             : 
   16349             :     /* Is it a table or a view? */
   16350       11864 :     if (tbinfo->relkind == RELKIND_VIEW)
   16351             :     {
   16352             :         PQExpBuffer result;
   16353             : 
   16354             :         /*
   16355             :          * Note: keep this code in sync with the is_view case in dumpRule()
   16356             :          */
   16357             : 
   16358        1036 :         reltypename = "VIEW";
   16359             : 
   16360        1036 :         appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
   16361             : 
   16362        1036 :         if (dopt->binary_upgrade)
   16363         102 :             binary_upgrade_set_pg_class_oids(fout, q,
   16364             :                                              tbinfo->dobj.catId.oid);
   16365             : 
   16366        1036 :         appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
   16367             : 
   16368        1036 :         if (tbinfo->dummy_view)
   16369          20 :             result = createDummyViewAsClause(fout, tbinfo);
   16370             :         else
   16371             :         {
   16372        1016 :             if (nonemptyReloptions(tbinfo->reloptions))
   16373             :             {
   16374         126 :                 appendPQExpBufferStr(q, " WITH (");
   16375         126 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   16376         126 :                 appendPQExpBufferChar(q, ')');
   16377             :             }
   16378        1016 :             result = createViewAsClause(fout, tbinfo);
   16379             :         }
   16380        1036 :         appendPQExpBuffer(q, " AS\n%s", result->data);
   16381        1036 :         destroyPQExpBuffer(result);
   16382             : 
   16383        1036 :         if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
   16384          68 :             appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
   16385        1036 :         appendPQExpBufferStr(q, ";\n");
   16386             :     }
   16387             :     else
   16388             :     {
   16389       10828 :         char       *partkeydef = NULL;
   16390       10828 :         char       *ftoptions = NULL;
   16391       10828 :         char       *srvname = NULL;
   16392       10828 :         const char *foreign = "";
   16393             : 
   16394             :         /*
   16395             :          * Set reltypename, and collect any relkind-specific data that we
   16396             :          * didn't fetch during getTables().
   16397             :          */
   16398       10828 :         switch (tbinfo->relkind)
   16399             :         {
   16400        1052 :             case RELKIND_PARTITIONED_TABLE:
   16401             :                 {
   16402        1052 :                     PQExpBuffer query = createPQExpBuffer();
   16403             :                     PGresult   *res;
   16404             : 
   16405        1052 :                     reltypename = "TABLE";
   16406             : 
   16407             :                     /* retrieve partition key definition */
   16408        1052 :                     appendPQExpBuffer(query,
   16409             :                                       "SELECT pg_get_partkeydef('%u')",
   16410             :                                       tbinfo->dobj.catId.oid);
   16411        1052 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16412        1052 :                     partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
   16413        1052 :                     PQclear(res);
   16414        1052 :                     destroyPQExpBuffer(query);
   16415        1052 :                     break;
   16416             :                 }
   16417          72 :             case RELKIND_FOREIGN_TABLE:
   16418             :                 {
   16419          72 :                     PQExpBuffer query = createPQExpBuffer();
   16420             :                     PGresult   *res;
   16421             :                     int         i_srvname;
   16422             :                     int         i_ftoptions;
   16423             : 
   16424          72 :                     reltypename = "FOREIGN TABLE";
   16425             : 
   16426             :                     /* retrieve name of foreign server and generic options */
   16427          72 :                     appendPQExpBuffer(query,
   16428             :                                       "SELECT fs.srvname, "
   16429             :                                       "pg_catalog.array_to_string(ARRAY("
   16430             :                                       "SELECT pg_catalog.quote_ident(option_name) || "
   16431             :                                       "' ' || pg_catalog.quote_literal(option_value) "
   16432             :                                       "FROM pg_catalog.pg_options_to_table(ftoptions) "
   16433             :                                       "ORDER BY option_name"
   16434             :                                       "), E',\n    ') AS ftoptions "
   16435             :                                       "FROM pg_catalog.pg_foreign_table ft "
   16436             :                                       "JOIN pg_catalog.pg_foreign_server fs "
   16437             :                                       "ON (fs.oid = ft.ftserver) "
   16438             :                                       "WHERE ft.ftrelid = '%u'",
   16439             :                                       tbinfo->dobj.catId.oid);
   16440          72 :                     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   16441          72 :                     i_srvname = PQfnumber(res, "srvname");
   16442          72 :                     i_ftoptions = PQfnumber(res, "ftoptions");
   16443          72 :                     srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
   16444          72 :                     ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
   16445          72 :                     PQclear(res);
   16446          72 :                     destroyPQExpBuffer(query);
   16447             : 
   16448          72 :                     foreign = "FOREIGN ";
   16449          72 :                     break;
   16450             :                 }
   16451         760 :             case RELKIND_MATVIEW:
   16452         760 :                 reltypename = "MATERIALIZED VIEW";
   16453         760 :                 break;
   16454        8944 :             default:
   16455        8944 :                 reltypename = "TABLE";
   16456        8944 :                 break;
   16457             :         }
   16458             : 
   16459       10828 :         numParents = tbinfo->numParents;
   16460       10828 :         parents = tbinfo->parents;
   16461             : 
   16462       10828 :         appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
   16463             : 
   16464       10828 :         if (dopt->binary_upgrade)
   16465        1518 :             binary_upgrade_set_pg_class_oids(fout, q,
   16466             :                                              tbinfo->dobj.catId.oid);
   16467             : 
   16468             :         /*
   16469             :          * PostgreSQL 18 has disabled UNLOGGED for partitioned tables, so
   16470             :          * ignore it when dumping if it was set in this case.
   16471             :          */
   16472       10828 :         appendPQExpBuffer(q, "CREATE %s%s %s",
   16473       10828 :                           (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
   16474          40 :                            tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ?
   16475             :                           "UNLOGGED " : "",
   16476             :                           reltypename,
   16477             :                           qualrelname);
   16478             : 
   16479             :         /*
   16480             :          * Attach to type, if reloftype; except in case of a binary upgrade,
   16481             :          * we dump the table normally and attach it to the type afterward.
   16482             :          */
   16483       10828 :         if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
   16484          48 :             appendPQExpBuffer(q, " OF %s",
   16485             :                               getFormattedTypeName(fout, tbinfo->reloftype,
   16486             :                                                    zeroIsError));
   16487             : 
   16488       10828 :         if (tbinfo->relkind != RELKIND_MATVIEW)
   16489             :         {
   16490             :             /* Dump the attributes */
   16491       10068 :             actual_atts = 0;
   16492       48920 :             for (j = 0; j < tbinfo->numatts; j++)
   16493             :             {
   16494             :                 /*
   16495             :                  * Normally, dump if it's locally defined in this table, and
   16496             :                  * not dropped.  But for binary upgrade, we'll dump all the
   16497             :                  * columns, and then fix up the dropped and nonlocal cases
   16498             :                  * below.
   16499             :                  */
   16500       38852 :                 if (shouldPrintColumn(dopt, tbinfo, j))
   16501             :                 {
   16502             :                     bool        print_default;
   16503             :                     bool        print_notnull;
   16504             : 
   16505             :                     /*
   16506             :                      * Default value --- suppress if to be printed separately
   16507             :                      * or not at all.
   16508             :                      */
   16509       76076 :                     print_default = (tbinfo->attrdefs[j] != NULL &&
   16510       38952 :                                      tbinfo->attrdefs[j]->dobj.dump &&
   16511        1926 :                                      !tbinfo->attrdefs[j]->separate);
   16512             : 
   16513             :                     /*
   16514             :                      * Not Null constraint --- print it if it is locally
   16515             :                      * defined, or if binary upgrade.  (In the latter case, we
   16516             :                      * reset conislocal below.)
   16517             :                      */
   16518       41256 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   16519        4230 :                                      (tbinfo->notnull_islocal[j] ||
   16520        1130 :                                       dopt->binary_upgrade ||
   16521         974 :                                       tbinfo->ispartition));
   16522             : 
   16523             :                     /*
   16524             :                      * Skip column if fully defined by reloftype, except in
   16525             :                      * binary upgrade
   16526             :                      */
   16527       37026 :                     if (OidIsValid(tbinfo->reloftype) &&
   16528         100 :                         !print_default && !print_notnull &&
   16529          60 :                         !dopt->binary_upgrade)
   16530          48 :                         continue;
   16531             : 
   16532             :                     /* Format properly if not first attr */
   16533       36978 :                     if (actual_atts == 0)
   16534        9564 :                         appendPQExpBufferStr(q, " (");
   16535             :                     else
   16536       27414 :                         appendPQExpBufferChar(q, ',');
   16537       36978 :                     appendPQExpBufferStr(q, "\n    ");
   16538       36978 :                     actual_atts++;
   16539             : 
   16540             :                     /* Attribute name */
   16541       36978 :                     appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
   16542             : 
   16543       36978 :                     if (tbinfo->attisdropped[j])
   16544             :                     {
   16545             :                         /*
   16546             :                          * ALTER TABLE DROP COLUMN clears
   16547             :                          * pg_attribute.atttypid, so we will not have gotten a
   16548             :                          * valid type name; insert INTEGER as a stopgap. We'll
   16549             :                          * clean things up later.
   16550             :                          */
   16551         168 :                         appendPQExpBufferStr(q, " INTEGER /* dummy */");
   16552             :                         /* and skip to the next column */
   16553         168 :                         continue;
   16554             :                     }
   16555             : 
   16556             :                     /*
   16557             :                      * Attribute type; print it except when creating a typed
   16558             :                      * table ('OF type_name'), but in binary-upgrade mode,
   16559             :                      * print it in that case too.
   16560             :                      */
   16561       36810 :                     if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
   16562             :                     {
   16563       36778 :                         appendPQExpBuffer(q, " %s",
   16564       36778 :                                           tbinfo->atttypnames[j]);
   16565             :                     }
   16566             : 
   16567       36810 :                     if (print_default)
   16568             :                     {
   16569        1658 :                         if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
   16570         556 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
   16571         556 :                                               tbinfo->attrdefs[j]->adef_expr);
   16572        1102 :                         else if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_VIRTUAL)
   16573         370 :                             appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s)",
   16574         370 :                                               tbinfo->attrdefs[j]->adef_expr);
   16575             :                         else
   16576         732 :                             appendPQExpBuffer(q, " DEFAULT %s",
   16577         732 :                                               tbinfo->attrdefs[j]->adef_expr);
   16578             :                     }
   16579             : 
   16580       41040 :                     print_notnull = (tbinfo->notnull_constrs[j] != NULL &&
   16581        4230 :                                      (tbinfo->notnull_islocal[j] ||
   16582        1130 :                                       dopt->binary_upgrade ||
   16583         974 :                                       tbinfo->ispartition));
   16584             : 
   16585       36810 :                     if (print_notnull)
   16586             :                     {
   16587        4164 :                         if (tbinfo->notnull_constrs[j][0] == '\0')
   16588        3028 :                             appendPQExpBufferStr(q, " NOT NULL");
   16589             :                         else
   16590        1136 :                             appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
   16591        1136 :                                               fmtId(tbinfo->notnull_constrs[j]));
   16592             : 
   16593        4164 :                         if (tbinfo->notnull_noinh[j])
   16594           0 :                             appendPQExpBufferStr(q, " NO INHERIT");
   16595             :                     }
   16596             : 
   16597             :                     /* Add collation if not default for the type */
   16598       36810 :                     if (OidIsValid(tbinfo->attcollation[j]))
   16599             :                     {
   16600             :                         CollInfo   *coll;
   16601             : 
   16602         394 :                         coll = findCollationByOid(tbinfo->attcollation[j]);
   16603         394 :                         if (coll)
   16604         394 :                             appendPQExpBuffer(q, " COLLATE %s",
   16605         394 :                                               fmtQualifiedDumpable(coll));
   16606             :                     }
   16607             :                 }
   16608             : 
   16609             :                 /*
   16610             :                  * On the other hand, if we choose not to print a column
   16611             :                  * (likely because it is created by inheritance), but the
   16612             :                  * column has a locally-defined not-null constraint, we need
   16613             :                  * to dump the constraint as a standalone object.
   16614             :                  *
   16615             :                  * This syntax isn't SQL-conforming, but if you wanted
   16616             :                  * standard output you wouldn't be creating non-standard
   16617             :                  * objects to begin with.
   16618             :                  */
   16619       38636 :                 if (!shouldPrintColumn(dopt, tbinfo, j) &&
   16620        1826 :                     !tbinfo->attisdropped[j] &&
   16621        1096 :                     tbinfo->notnull_constrs[j] != NULL &&
   16622         202 :                     tbinfo->notnull_islocal[j])
   16623             :                 {
   16624             :                     /* Format properly if not first attr */
   16625          32 :                     if (actual_atts == 0)
   16626          24 :                         appendPQExpBufferStr(q, " (");
   16627             :                     else
   16628           8 :                         appendPQExpBufferChar(q, ',');
   16629          32 :                     appendPQExpBufferStr(q, "\n    ");
   16630          32 :                     actual_atts++;
   16631             : 
   16632          32 :                     if (tbinfo->notnull_constrs[j][0] == '\0')
   16633           8 :                         appendPQExpBuffer(q, "NOT NULL %s",
   16634           8 :                                           fmtId(tbinfo->attnames[j]));
   16635             :                     else
   16636          48 :                         appendPQExpBuffer(q, "CONSTRAINT %s NOT NULL %s",
   16637          24 :                                           tbinfo->notnull_constrs[j],
   16638          24 :                                           fmtId(tbinfo->attnames[j]));
   16639             :                 }
   16640             :             }
   16641             : 
   16642             :             /*
   16643             :              * Add non-inherited CHECK constraints, if any.
   16644             :              *
   16645             :              * For partitions, we need to include check constraints even if
   16646             :              * they're not defined locally, because the ALTER TABLE ATTACH
   16647             :              * PARTITION that we'll emit later expects the constraint to be
   16648             :              * there.  (No need to fix conislocal: ATTACH PARTITION does that)
   16649             :              */
   16650       11254 :             for (j = 0; j < tbinfo->ncheck; j++)
   16651             :             {
   16652        1186 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   16653             : 
   16654        1186 :                 if (constr->separate ||
   16655        1046 :                     (!constr->conislocal && !tbinfo->ispartition))
   16656         218 :                     continue;
   16657             : 
   16658         968 :                 if (actual_atts == 0)
   16659          32 :                     appendPQExpBufferStr(q, " (\n    ");
   16660             :                 else
   16661         936 :                     appendPQExpBufferStr(q, ",\n    ");
   16662             : 
   16663         968 :                 appendPQExpBuffer(q, "CONSTRAINT %s ",
   16664         968 :                                   fmtId(constr->dobj.name));
   16665         968 :                 appendPQExpBufferStr(q, constr->condef);
   16666             : 
   16667         968 :                 actual_atts++;
   16668             :             }
   16669             : 
   16670       10068 :             if (actual_atts)
   16671        9620 :                 appendPQExpBufferStr(q, "\n)");
   16672         448 :             else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
   16673             :             {
   16674             :                 /*
   16675             :                  * No attributes? we must have a parenthesized attribute list,
   16676             :                  * even though empty, when not using the OF TYPE syntax.
   16677             :                  */
   16678         424 :                 appendPQExpBufferStr(q, " (\n)");
   16679             :             }
   16680             : 
   16681             :             /*
   16682             :              * Emit the INHERITS clause (not for partitions), except in
   16683             :              * binary-upgrade mode.
   16684             :              */
   16685       10068 :             if (numParents > 0 && !tbinfo->ispartition &&
   16686         738 :                 !dopt->binary_upgrade)
   16687             :             {
   16688         628 :                 appendPQExpBufferStr(q, "\nINHERITS (");
   16689        1320 :                 for (k = 0; k < numParents; k++)
   16690             :                 {
   16691         692 :                     TableInfo  *parentRel = parents[k];
   16692             : 
   16693         692 :                     if (k > 0)
   16694          64 :                         appendPQExpBufferStr(q, ", ");
   16695         692 :                     appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
   16696             :                 }
   16697         628 :                 appendPQExpBufferChar(q, ')');
   16698             :             }
   16699             : 
   16700       10068 :             if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   16701        1052 :                 appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
   16702             : 
   16703       10068 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
   16704          72 :                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
   16705             :         }
   16706             : 
   16707       21368 :         if (nonemptyReloptions(tbinfo->reloptions) ||
   16708       10540 :             nonemptyReloptions(tbinfo->toast_reloptions))
   16709             :         {
   16710         288 :             bool        addcomma = false;
   16711             : 
   16712         288 :             appendPQExpBufferStr(q, "\nWITH (");
   16713         288 :             if (nonemptyReloptions(tbinfo->reloptions))
   16714             :             {
   16715         288 :                 addcomma = true;
   16716         288 :                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
   16717             :             }
   16718         288 :             if (nonemptyReloptions(tbinfo->toast_reloptions))
   16719             :             {
   16720          10 :                 if (addcomma)
   16721          10 :                     appendPQExpBufferStr(q, ", ");
   16722          10 :                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
   16723             :                                         fout);
   16724             :             }
   16725         288 :             appendPQExpBufferChar(q, ')');
   16726             :         }
   16727             : 
   16728             :         /* Dump generic options if any */
   16729       10828 :         if (ftoptions && ftoptions[0])
   16730          68 :             appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
   16731             : 
   16732             :         /*
   16733             :          * For materialized views, create the AS clause just like a view. At
   16734             :          * this point, we always mark the view as not populated.
   16735             :          */
   16736       10828 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16737             :         {
   16738             :             PQExpBuffer result;
   16739             : 
   16740         760 :             result = createViewAsClause(fout, tbinfo);
   16741         760 :             appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
   16742             :                               result->data);
   16743         760 :             destroyPQExpBuffer(result);
   16744             :         }
   16745             :         else
   16746       10068 :             appendPQExpBufferStr(q, ";\n");
   16747             : 
   16748             :         /* Materialized views can depend on extensions */
   16749       10828 :         if (tbinfo->relkind == RELKIND_MATVIEW)
   16750         760 :             append_depends_on_extension(fout, q, &tbinfo->dobj,
   16751             :                                         "pg_catalog.pg_class",
   16752             :                                         "MATERIALIZED VIEW",
   16753             :                                         qualrelname);
   16754             : 
   16755             :         /*
   16756             :          * in binary upgrade mode, update the catalog with any missing values
   16757             :          * that might be present.
   16758             :          */
   16759       10828 :         if (dopt->binary_upgrade)
   16760             :         {
   16761        7626 :             for (j = 0; j < tbinfo->numatts; j++)
   16762             :             {
   16763        6108 :                 if (tbinfo->attmissingval[j][0] != '\0')
   16764             :                 {
   16765           4 :                     appendPQExpBufferStr(q, "\n-- set missing value.\n");
   16766           4 :                     appendPQExpBufferStr(q,
   16767             :                                          "SELECT pg_catalog.binary_upgrade_set_missing_value(");
   16768           4 :                     appendStringLiteralAH(q, qualrelname, fout);
   16769           4 :                     appendPQExpBufferStr(q, "::pg_catalog.regclass,");
   16770           4 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16771           4 :                     appendPQExpBufferChar(q, ',');
   16772           4 :                     appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
   16773           4 :                     appendPQExpBufferStr(q, ");\n\n");
   16774             :                 }
   16775             :             }
   16776             :         }
   16777             : 
   16778             :         /*
   16779             :          * To create binary-compatible heap files, we have to ensure the same
   16780             :          * physical column order, including dropped columns, as in the
   16781             :          * original.  Therefore, we create dropped columns above and drop them
   16782             :          * here, also updating their attlen/attalign values so that the
   16783             :          * dropped column can be skipped properly.  (We do not bother with
   16784             :          * restoring the original attbyval setting.)  Also, inheritance
   16785             :          * relationships are set up by doing ALTER TABLE INHERIT rather than
   16786             :          * using an INHERITS clause --- the latter would possibly mess up the
   16787             :          * column order.  That also means we have to take care about setting
   16788             :          * attislocal correctly, plus fix up any inherited CHECK constraints.
   16789             :          * Analogously, we set up typed tables using ALTER TABLE / OF here.
   16790             :          *
   16791             :          * We process foreign and partitioned tables here, even though they
   16792             :          * lack heap storage, because they can participate in inheritance
   16793             :          * relationships and we want this stuff to be consistent across the
   16794             :          * inheritance tree.  We can exclude indexes, toast tables, sequences
   16795             :          * and matviews, even though they have storage, because we don't
   16796             :          * support altering or dropping columns in them, nor can they be part
   16797             :          * of inheritance trees.
   16798             :          */
   16799       10828 :         if (dopt->binary_upgrade &&
   16800        1518 :             (tbinfo->relkind == RELKIND_RELATION ||
   16801         212 :              tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
   16802         210 :              tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
   16803             :         {
   16804             :             bool        firstitem;
   16805             :             bool        firstitem_extra;
   16806             : 
   16807             :             /*
   16808             :              * Drop any dropped columns.  Merge the pg_attribute manipulations
   16809             :              * into a single SQL command, so that we don't cause repeated
   16810             :              * relcache flushes on the target table.  Otherwise we risk O(N^2)
   16811             :              * relcache bloat while dropping N columns.
   16812             :              */
   16813        1482 :             resetPQExpBuffer(extra);
   16814        1482 :             firstitem = true;
   16815        7546 :             for (j = 0; j < tbinfo->numatts; j++)
   16816             :             {
   16817        6064 :                 if (tbinfo->attisdropped[j])
   16818             :                 {
   16819         168 :                     if (firstitem)
   16820             :                     {
   16821          76 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped columns.\n"
   16822             :                                              "UPDATE pg_catalog.pg_attribute\n"
   16823             :                                              "SET attlen = v.dlen, "
   16824             :                                              "attalign = v.dalign, "
   16825             :                                              "attbyval = false\n"
   16826             :                                              "FROM (VALUES ");
   16827          76 :                         firstitem = false;
   16828             :                     }
   16829             :                     else
   16830          92 :                         appendPQExpBufferStr(q, ",\n             ");
   16831         168 :                     appendPQExpBufferChar(q, '(');
   16832         168 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16833         168 :                     appendPQExpBuffer(q, ", %d, '%c')",
   16834         168 :                                       tbinfo->attlen[j],
   16835         168 :                                       tbinfo->attalign[j]);
   16836             :                     /* The ALTER ... DROP COLUMN commands must come after */
   16837         168 :                     appendPQExpBuffer(extra, "ALTER %sTABLE ONLY %s ",
   16838             :                                       foreign, qualrelname);
   16839         168 :                     appendPQExpBuffer(extra, "DROP COLUMN %s;\n",
   16840         168 :                                       fmtId(tbinfo->attnames[j]));
   16841             :                 }
   16842             :             }
   16843        1482 :             if (!firstitem)
   16844             :             {
   16845          76 :                 appendPQExpBufferStr(q, ") v(dname, dlen, dalign)\n"
   16846             :                                      "WHERE attrelid = ");
   16847          76 :                 appendStringLiteralAH(q, qualrelname, fout);
   16848          76 :                 appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   16849             :                                      "  AND attname = v.dname;\n");
   16850             :                 /* Now we can issue the actual DROP COLUMN commands */
   16851          76 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   16852             :             }
   16853             : 
   16854             :             /*
   16855             :              * Fix up inherited columns.  As above, do the pg_attribute
   16856             :              * manipulations in a single SQL command.
   16857             :              */
   16858        1482 :             firstitem = true;
   16859        7546 :             for (j = 0; j < tbinfo->numatts; j++)
   16860             :             {
   16861        6064 :                 if (!tbinfo->attisdropped[j] &&
   16862        5896 :                     !tbinfo->attislocal[j])
   16863             :                 {
   16864        1158 :                     if (firstitem)
   16865             :                     {
   16866         504 :                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited columns.\n");
   16867         504 :                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
   16868             :                                              "SET attislocal = false\n"
   16869             :                                              "WHERE attrelid = ");
   16870         504 :                         appendStringLiteralAH(q, qualrelname, fout);
   16871         504 :                         appendPQExpBufferStr(q, "::pg_catalog.regclass\n"
   16872             :                                              "  AND attname IN (");
   16873         504 :                         firstitem = false;
   16874             :                     }
   16875             :                     else
   16876         654 :                         appendPQExpBufferStr(q, ", ");
   16877        1158 :                     appendStringLiteralAH(q, tbinfo->attnames[j], fout);
   16878             :                 }
   16879             :             }
   16880        1482 :             if (!firstitem)
   16881         504 :                 appendPQExpBufferStr(q, ");\n");
   16882             : 
   16883             :             /*
   16884             :              * Fix up not-null constraints that come from inheritance.  As
   16885             :              * above, do the pg_constraint manipulations in a single SQL
   16886             :              * command.  (Actually, two in special cases, if we're doing an
   16887             :              * upgrade from < 18).
   16888             :              */
   16889        1482 :             firstitem = true;
   16890        1482 :             firstitem_extra = true;
   16891        1482 :             resetPQExpBuffer(extra);
   16892        7546 :             for (j = 0; j < tbinfo->numatts; j++)
   16893             :             {
   16894             :                 /*
   16895             :                  * If a not-null constraint comes from inheritance, reset
   16896             :                  * conislocal.  The inhcount is fixed by ALTER TABLE INHERIT,
   16897             :                  * below.  Special hack: in versions < 18, columns with no
   16898             :                  * local definition need their constraint to be matched by
   16899             :                  * column number in conkeys instead of by constraint name,
   16900             :                  * because the latter is not available.  (We distinguish the
   16901             :                  * case because the constraint name is the empty string.)
   16902             :                  */
   16903        6064 :                 if (tbinfo->notnull_constrs[j] != NULL &&
   16904         538 :                     !tbinfo->notnull_islocal[j])
   16905             :                 {
   16906         156 :                     if (tbinfo->notnull_constrs[j][0] != '\0')
   16907             :                     {
   16908         130 :                         if (firstitem)
   16909             :                         {
   16910         114 :                             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
   16911             :                                                  "SET conislocal = false\n"
   16912             :                                                  "WHERE contype = 'n' AND conrelid = ");
   16913         114 :                             appendStringLiteralAH(q, qualrelname, fout);
   16914         114 :                             appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
   16915             :                                                  "conname IN (");
   16916         114 :                             firstitem = false;
   16917             :                         }
   16918             :                         else
   16919          16 :                             appendPQExpBufferStr(q, ", ");
   16920         130 :                         appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
   16921             :                     }
   16922             :                     else
   16923             :                     {
   16924          26 :                         if (firstitem_extra)
   16925             :                         {
   16926          26 :                             appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   16927             :                                                  "SET conislocal = false\n"
   16928             :                                                  "WHERE contype = 'n' AND conrelid = ");
   16929          26 :                             appendStringLiteralAH(extra, qualrelname, fout);
   16930          26 :                             appendPQExpBufferStr(extra, "::pg_catalog.regclass AND\n"
   16931             :                                                  "conkey IN (");
   16932          26 :                             firstitem_extra = false;
   16933             :                         }
   16934             :                         else
   16935           0 :                             appendPQExpBufferStr(extra, ", ");
   16936          26 :                         appendPQExpBuffer(extra, "'{%d}'", j + 1);
   16937             :                     }
   16938             :                 }
   16939             :             }
   16940        1482 :             if (!firstitem)
   16941         114 :                 appendPQExpBufferStr(q, ");\n");
   16942        1482 :             if (!firstitem_extra)
   16943          26 :                 appendPQExpBufferStr(extra, ");\n");
   16944             : 
   16945        1482 :             if (extra->len > 0)
   16946          26 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   16947             : 
   16948             :             /*
   16949             :              * Add inherited CHECK constraints, if any.
   16950             :              *
   16951             :              * For partitions, they were already dumped, and conislocal
   16952             :              * doesn't need fixing.
   16953             :              *
   16954             :              * As above, issue only one direct manipulation of pg_constraint.
   16955             :              * Although it is tempting to merge the ALTER ADD CONSTRAINT
   16956             :              * commands into one as well, refrain for now due to concern about
   16957             :              * possible backend memory bloat if there are many such
   16958             :              * constraints.
   16959             :              */
   16960        1482 :             resetPQExpBuffer(extra);
   16961        1482 :             firstitem = true;
   16962        1606 :             for (k = 0; k < tbinfo->ncheck; k++)
   16963             :             {
   16964         124 :                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
   16965             : 
   16966         124 :                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
   16967         120 :                     continue;
   16968             : 
   16969           4 :                 if (firstitem)
   16970           4 :                     appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraints.\n");
   16971           4 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
   16972             :                                   foreign, qualrelname,
   16973           4 :                                   fmtId(constr->dobj.name),
   16974             :                                   constr->condef);
   16975             :                 /* Update pg_constraint after all the ALTER TABLEs */
   16976           4 :                 if (firstitem)
   16977             :                 {
   16978           4 :                     appendPQExpBufferStr(extra, "UPDATE pg_catalog.pg_constraint\n"
   16979             :                                          "SET conislocal = false\n"
   16980             :                                          "WHERE contype = 'c' AND conrelid = ");
   16981           4 :                     appendStringLiteralAH(extra, qualrelname, fout);
   16982           4 :                     appendPQExpBufferStr(extra, "::pg_catalog.regclass\n");
   16983           4 :                     appendPQExpBufferStr(extra, "  AND conname IN (");
   16984           4 :                     firstitem = false;
   16985             :                 }
   16986             :                 else
   16987           0 :                     appendPQExpBufferStr(extra, ", ");
   16988           4 :                 appendStringLiteralAH(extra, constr->dobj.name, fout);
   16989             :             }
   16990        1482 :             if (!firstitem)
   16991             :             {
   16992           4 :                 appendPQExpBufferStr(extra, ");\n");
   16993           4 :                 appendBinaryPQExpBuffer(q, extra->data, extra->len);
   16994             :             }
   16995             : 
   16996        1482 :             if (numParents > 0 && !tbinfo->ispartition)
   16997             :             {
   16998         110 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
   16999         236 :                 for (k = 0; k < numParents; k++)
   17000             :                 {
   17001         126 :                     TableInfo  *parentRel = parents[k];
   17002             : 
   17003         126 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
   17004             :                                       qualrelname,
   17005         126 :                                       fmtQualifiedDumpable(parentRel));
   17006             :                 }
   17007             :             }
   17008             : 
   17009        1482 :             if (OidIsValid(tbinfo->reloftype))
   17010             :             {
   17011          12 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
   17012          12 :                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
   17013             :                                   qualrelname,
   17014             :                                   getFormattedTypeName(fout, tbinfo->reloftype,
   17015             :                                                        zeroIsError));
   17016             :             }
   17017             :         }
   17018             : 
   17019             :         /*
   17020             :          * In binary_upgrade mode, arrange to restore the old relfrozenxid and
   17021             :          * relminmxid of all vacuumable relations.  (While vacuum.c processes
   17022             :          * TOAST tables semi-independently, here we see them only as children
   17023             :          * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
   17024             :          * child toast table is handled below.)
   17025             :          */
   17026       10828 :         if (dopt->binary_upgrade &&
   17027        1518 :             (tbinfo->relkind == RELKIND_RELATION ||
   17028         212 :              tbinfo->relkind == RELKIND_MATVIEW))
   17029             :         {
   17030        1342 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
   17031        1342 :             appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17032             :                               "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17033             :                               "WHERE oid = ",
   17034             :                               tbinfo->frozenxid, tbinfo->minmxid);
   17035        1342 :             appendStringLiteralAH(q, qualrelname, fout);
   17036        1342 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17037             : 
   17038        1342 :             if (tbinfo->toast_oid)
   17039             :             {
   17040             :                 /*
   17041             :                  * The toast table will have the same OID at restore, so we
   17042             :                  * can safely target it by OID.
   17043             :                  */
   17044         552 :                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
   17045         552 :                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
   17046             :                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
   17047             :                                   "WHERE oid = '%u';\n",
   17048             :                                   tbinfo->toast_frozenxid,
   17049             :                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
   17050             :             }
   17051             :         }
   17052             : 
   17053             :         /*
   17054             :          * In binary_upgrade mode, restore matviews' populated status by
   17055             :          * poking pg_class directly.  This is pretty ugly, but we can't use
   17056             :          * REFRESH MATERIALIZED VIEW since it's possible that some underlying
   17057             :          * matview is not populated even though this matview is; in any case,
   17058             :          * we want to transfer the matview's heap storage, not run REFRESH.
   17059             :          */
   17060       10828 :         if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
   17061          36 :             tbinfo->relispopulated)
   17062             :         {
   17063          32 :             appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
   17064          32 :             appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
   17065             :                                  "SET relispopulated = 't'\n"
   17066             :                                  "WHERE oid = ");
   17067          32 :             appendStringLiteralAH(q, qualrelname, fout);
   17068          32 :             appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
   17069             :         }
   17070             : 
   17071             :         /*
   17072             :          * Dump additional per-column properties that we can't handle in the
   17073             :          * main CREATE TABLE command.
   17074             :          */
   17075       50596 :         for (j = 0; j < tbinfo->numatts; j++)
   17076             :         {
   17077             :             /* None of this applies to dropped columns */
   17078       39768 :             if (tbinfo->attisdropped[j])
   17079         898 :                 continue;
   17080             : 
   17081             :             /*
   17082             :              * Dump per-column statistics information. We only issue an ALTER
   17083             :              * TABLE statement if the attstattarget entry for this column is
   17084             :              * not the default value.
   17085             :              */
   17086       38870 :             if (tbinfo->attstattarget[j] >= 0)
   17087          68 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
   17088             :                                   foreign, qualrelname,
   17089          68 :                                   fmtId(tbinfo->attnames[j]),
   17090          68 :                                   tbinfo->attstattarget[j]);
   17091             : 
   17092             :             /*
   17093             :              * Dump per-column storage information.  The statement is only
   17094             :              * dumped if the storage has been changed from the type's default.
   17095             :              */
   17096       38870 :             if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
   17097             :             {
   17098         166 :                 switch (tbinfo->attstorage[j])
   17099             :                 {
   17100          20 :                     case TYPSTORAGE_PLAIN:
   17101          20 :                         storage = "PLAIN";
   17102          20 :                         break;
   17103          78 :                     case TYPSTORAGE_EXTERNAL:
   17104          78 :                         storage = "EXTERNAL";
   17105          78 :                         break;
   17106           0 :                     case TYPSTORAGE_EXTENDED:
   17107           0 :                         storage = "EXTENDED";
   17108           0 :                         break;
   17109          68 :                     case TYPSTORAGE_MAIN:
   17110          68 :                         storage = "MAIN";
   17111          68 :                         break;
   17112           0 :                     default:
   17113           0 :                         storage = NULL;
   17114             :                 }
   17115             : 
   17116             :                 /*
   17117             :                  * Only dump the statement if it's a storage type we recognize
   17118             :                  */
   17119         166 :                 if (storage != NULL)
   17120         166 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
   17121             :                                       foreign, qualrelname,
   17122         166 :                                       fmtId(tbinfo->attnames[j]),
   17123             :                                       storage);
   17124             :             }
   17125             : 
   17126             :             /*
   17127             :              * Dump per-column compression, if it's been set.
   17128             :              */
   17129       38870 :             if (!dopt->no_toast_compression)
   17130             :             {
   17131             :                 const char *cmname;
   17132             : 
   17133       38690 :                 switch (tbinfo->attcompression[j])
   17134             :                 {
   17135         116 :                     case 'p':
   17136         116 :                         cmname = "pglz";
   17137         116 :                         break;
   17138         192 :                     case 'l':
   17139         192 :                         cmname = "lz4";
   17140         192 :                         break;
   17141       38382 :                     default:
   17142       38382 :                         cmname = NULL;
   17143       38382 :                         break;
   17144             :                 }
   17145             : 
   17146       38690 :                 if (cmname != NULL)
   17147         308 :                     appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
   17148             :                                       foreign, qualrelname,
   17149         308 :                                       fmtId(tbinfo->attnames[j]),
   17150             :                                       cmname);
   17151             :             }
   17152             : 
   17153             :             /*
   17154             :              * Dump per-column attributes.
   17155             :              */
   17156       38870 :             if (tbinfo->attoptions[j][0] != '\0')
   17157          68 :                 appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
   17158             :                                   foreign, qualrelname,
   17159          68 :                                   fmtId(tbinfo->attnames[j]),
   17160          68 :                                   tbinfo->attoptions[j]);
   17161             : 
   17162             :             /*
   17163             :              * Dump per-column fdw options.
   17164             :              */
   17165       38870 :             if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
   17166          72 :                 tbinfo->attfdwoptions[j][0] != '\0')
   17167          68 :                 appendPQExpBuffer(q,
   17168             :                                   "ALTER FOREIGN TABLE ONLY %s ALTER COLUMN %s OPTIONS (\n"
   17169             :                                   "    %s\n"
   17170             :                                   ");\n",
   17171             :                                   qualrelname,
   17172          68 :                                   fmtId(tbinfo->attnames[j]),
   17173          68 :                                   tbinfo->attfdwoptions[j]);
   17174             :         }                       /* end loop over columns */
   17175             : 
   17176       10828 :         free(partkeydef);
   17177       10828 :         free(ftoptions);
   17178       10828 :         free(srvname);
   17179             :     }
   17180             : 
   17181             :     /*
   17182             :      * dump properties we only have ALTER TABLE syntax for
   17183             :      */
   17184       11864 :     if ((tbinfo->relkind == RELKIND_RELATION ||
   17185        2920 :          tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
   17186        1868 :          tbinfo->relkind == RELKIND_MATVIEW) &&
   17187       10756 :         tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
   17188             :     {
   17189         384 :         if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
   17190             :         {
   17191             :             /* nothing to do, will be set when the index is dumped */
   17192             :         }
   17193         384 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
   17194             :         {
   17195         384 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
   17196             :                               qualrelname);
   17197             :         }
   17198           0 :         else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
   17199             :         {
   17200           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
   17201             :                               qualrelname);
   17202             :         }
   17203             :     }
   17204             : 
   17205       11864 :     if (tbinfo->forcerowsec)
   17206          10 :         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
   17207             :                           qualrelname);
   17208             : 
   17209       11864 :     if (dopt->binary_upgrade)
   17210        1620 :         binary_upgrade_extension_member(q, &tbinfo->dobj,
   17211             :                                         reltypename, qrelname,
   17212        1620 :                                         tbinfo->dobj.namespace->dobj.name);
   17213             : 
   17214       11864 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17215             :     {
   17216       11864 :         char       *tablespace = NULL;
   17217       11864 :         char       *tableam = NULL;
   17218             : 
   17219             :         /*
   17220             :          * _selectTablespace() relies on tablespace-enabled objects in the
   17221             :          * default tablespace to have a tablespace of "" (empty string) versus
   17222             :          * non-tablespace-enabled objects to have a tablespace of NULL.
   17223             :          * getTables() sets tbinfo->reltablespace to "" for the default
   17224             :          * tablespace (not NULL).
   17225             :          */
   17226       11864 :         if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
   17227       10756 :             tablespace = tbinfo->reltablespace;
   17228             : 
   17229       11864 :         if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
   17230        2160 :             tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
   17231       10756 :             tableam = tbinfo->amname;
   17232             : 
   17233       11864 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   17234       11864 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   17235             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17236             :                                   .tablespace = tablespace,
   17237             :                                   .tableam = tableam,
   17238             :                                   .relkind = tbinfo->relkind,
   17239             :                                   .owner = tbinfo->rolname,
   17240             :                                   .description = reltypename,
   17241             :                                   .section = tbinfo->postponed_def ?
   17242             :                                   SECTION_POST_DATA : SECTION_PRE_DATA,
   17243             :                                   .createStmt = q->data,
   17244             :                                   .dropStmt = delq->data));
   17245             :     }
   17246             : 
   17247             :     /* Dump Table Comments */
   17248       11864 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17249         156 :         dumpTableComment(fout, tbinfo, reltypename);
   17250             : 
   17251             :     /* Dump Table Security Labels */
   17252       11864 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   17253           0 :         dumpTableSecLabel(fout, tbinfo, reltypename);
   17254             : 
   17255             :     /* Dump comments on inlined table constraints */
   17256       13050 :     for (j = 0; j < tbinfo->ncheck; j++)
   17257             :     {
   17258        1186 :         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
   17259             : 
   17260        1186 :         if (constr->separate || !constr->conislocal)
   17261         508 :             continue;
   17262             : 
   17263         678 :         if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
   17264          78 :             dumpTableConstraintComment(fout, constr);
   17265             :     }
   17266             : 
   17267       11864 :     destroyPQExpBuffer(q);
   17268       11864 :     destroyPQExpBuffer(delq);
   17269       11864 :     destroyPQExpBuffer(extra);
   17270       11864 :     free(qrelname);
   17271       11864 :     free(qualrelname);
   17272       11864 : }
   17273             : 
   17274             : /*
   17275             :  * dumpTableAttach
   17276             :  *    write to fout the commands to attach a child partition
   17277             :  *
   17278             :  * Child partitions are always made by creating them separately
   17279             :  * and then using ATTACH PARTITION, rather than using
   17280             :  * CREATE TABLE ... PARTITION OF.  This is important for preserving
   17281             :  * any possible discrepancy in column layout, to allow assigning the
   17282             :  * correct tablespace if different, and so that it's possible to restore
   17283             :  * a partition without restoring its parent.  (You'll get an error from
   17284             :  * the ATTACH PARTITION command, but that can be ignored, or skipped
   17285             :  * using "pg_restore -L" if you prefer.)  The last point motivates
   17286             :  * treating ATTACH PARTITION as a completely separate ArchiveEntry
   17287             :  * rather than emitting it within the child partition's ArchiveEntry.
   17288             :  */
   17289             : static void
   17290        2582 : dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
   17291             : {
   17292        2582 :     DumpOptions *dopt = fout->dopt;
   17293             :     PQExpBuffer q;
   17294             :     PGresult   *res;
   17295             :     char       *partbound;
   17296             : 
   17297             :     /* Do nothing if not dumping schema */
   17298        2582 :     if (!dopt->dumpSchema)
   17299          84 :         return;
   17300             : 
   17301        2498 :     q = createPQExpBuffer();
   17302             : 
   17303        2498 :     if (!fout->is_prepared[PREPQUERY_DUMPTABLEATTACH])
   17304             :     {
   17305             :         /* Set up query for partbound details */
   17306          90 :         appendPQExpBufferStr(q,
   17307             :                              "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
   17308             : 
   17309          90 :         appendPQExpBufferStr(q,
   17310             :                              "SELECT pg_get_expr(c.relpartbound, c.oid) "
   17311             :                              "FROM pg_class c "
   17312             :                              "WHERE c.oid = $1");
   17313             : 
   17314          90 :         ExecuteSqlStatement(fout, q->data);
   17315             : 
   17316          90 :         fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
   17317             :     }
   17318             : 
   17319        2498 :     printfPQExpBuffer(q,
   17320             :                       "EXECUTE dumpTableAttach('%u')",
   17321        2498 :                       attachinfo->partitionTbl->dobj.catId.oid);
   17322             : 
   17323        2498 :     res = ExecuteSqlQueryForSingleRow(fout, q->data);
   17324        2498 :     partbound = PQgetvalue(res, 0, 0);
   17325             : 
   17326             :     /* Perform ALTER TABLE on the parent */
   17327        2498 :     printfPQExpBuffer(q,
   17328             :                       "ALTER TABLE ONLY %s ",
   17329        2498 :                       fmtQualifiedDumpable(attachinfo->parentTbl));
   17330        2498 :     appendPQExpBuffer(q,
   17331             :                       "ATTACH PARTITION %s %s;\n",
   17332        2498 :                       fmtQualifiedDumpable(attachinfo->partitionTbl),
   17333             :                       partbound);
   17334             : 
   17335             :     /*
   17336             :      * There is no point in creating a drop query as the drop is done by table
   17337             :      * drop.  (If you think to change this, see also _printTocEntry().)
   17338             :      * Although this object doesn't really have ownership as such, set the
   17339             :      * owner field anyway to ensure that the command is run by the correct
   17340             :      * role at restore time.
   17341             :      */
   17342        2498 :     ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   17343        2498 :                  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   17344             :                               .namespace = attachinfo->dobj.namespace->dobj.name,
   17345             :                               .owner = attachinfo->partitionTbl->rolname,
   17346             :                               .description = "TABLE ATTACH",
   17347             :                               .section = SECTION_PRE_DATA,
   17348             :                               .createStmt = q->data));
   17349             : 
   17350        2498 :     PQclear(res);
   17351        2498 :     destroyPQExpBuffer(q);
   17352             : }
   17353             : 
   17354             : /*
   17355             :  * dumpAttrDef --- dump an attribute's default-value declaration
   17356             :  */
   17357             : static void
   17358        2002 : dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
   17359             : {
   17360        2002 :     DumpOptions *dopt = fout->dopt;
   17361        2002 :     TableInfo  *tbinfo = adinfo->adtable;
   17362        2002 :     int         adnum = adinfo->adnum;
   17363             :     PQExpBuffer q;
   17364             :     PQExpBuffer delq;
   17365             :     char       *qualrelname;
   17366             :     char       *tag;
   17367             :     char       *foreign;
   17368             : 
   17369             :     /* Do nothing if not dumping schema */
   17370        2002 :     if (!dopt->dumpSchema)
   17371           0 :         return;
   17372             : 
   17373             :     /* Skip if not "separate"; it was dumped in the table's definition */
   17374        2002 :     if (!adinfo->separate)
   17375        1658 :         return;
   17376             : 
   17377         344 :     q = createPQExpBuffer();
   17378         344 :     delq = createPQExpBuffer();
   17379             : 
   17380         344 :     qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
   17381             : 
   17382         344 :     foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   17383             : 
   17384         344 :     appendPQExpBuffer(q,
   17385             :                       "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
   17386         344 :                       foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
   17387             :                       adinfo->adef_expr);
   17388             : 
   17389         344 :     appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
   17390             :                       foreign, qualrelname,
   17391         344 :                       fmtId(tbinfo->attnames[adnum - 1]));
   17392             : 
   17393         344 :     tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
   17394             : 
   17395         344 :     if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17396         344 :         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
   17397         344 :                      ARCHIVE_OPTS(.tag = tag,
   17398             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   17399             :                                   .owner = tbinfo->rolname,
   17400             :                                   .description = "DEFAULT",
   17401             :                                   .section = SECTION_PRE_DATA,
   17402             :                                   .createStmt = q->data,
   17403             :                                   .dropStmt = delq->data));
   17404             : 
   17405         344 :     free(tag);
   17406         344 :     destroyPQExpBuffer(q);
   17407         344 :     destroyPQExpBuffer(delq);
   17408         344 :     free(qualrelname);
   17409             : }
   17410             : 
   17411             : /*
   17412             :  * getAttrName: extract the correct name for an attribute
   17413             :  *
   17414             :  * The array tblInfo->attnames[] only provides names of user attributes;
   17415             :  * if a system attribute number is supplied, we have to fake it.
   17416             :  * We also do a little bit of bounds checking for safety's sake.
   17417             :  */
   17418             : static const char *
   17419        4124 : getAttrName(int attrnum, const TableInfo *tblInfo)
   17420             : {
   17421        4124 :     if (attrnum > 0 && attrnum <= tblInfo->numatts)
   17422        4124 :         return tblInfo->attnames[attrnum - 1];
   17423           0 :     switch (attrnum)
   17424             :     {
   17425           0 :         case SelfItemPointerAttributeNumber:
   17426           0 :             return "ctid";
   17427           0 :         case MinTransactionIdAttributeNumber:
   17428           0 :             return "xmin";
   17429           0 :         case MinCommandIdAttributeNumber:
   17430           0 :             return "cmin";
   17431           0 :         case MaxTransactionIdAttributeNumber:
   17432           0 :             return "xmax";
   17433           0 :         case MaxCommandIdAttributeNumber:
   17434           0 :             return "cmax";
   17435           0 :         case TableOidAttributeNumber:
   17436           0 :             return "tableoid";
   17437             :     }
   17438           0 :     pg_fatal("invalid column number %d for table \"%s\"",
   17439             :              attrnum, tblInfo->dobj.name);
   17440             :     return NULL;                /* keep compiler quiet */
   17441             : }
   17442             : 
   17443             : /*
   17444             :  * dumpIndex
   17445             :  *    write out to fout a user-defined index
   17446             :  */
   17447             : static void
   17448        5184 : dumpIndex(Archive *fout, const IndxInfo *indxinfo)
   17449             : {
   17450        5184 :     DumpOptions *dopt = fout->dopt;
   17451        5184 :     TableInfo  *tbinfo = indxinfo->indextable;
   17452        5184 :     bool        is_constraint = (indxinfo->indexconstraint != 0);
   17453             :     PQExpBuffer q;
   17454             :     PQExpBuffer delq;
   17455             :     char       *qindxname;
   17456             :     char       *qqindxname;
   17457             : 
   17458             :     /* Do nothing if not dumping schema */
   17459        5184 :     if (!dopt->dumpSchema)
   17460         234 :         return;
   17461             : 
   17462        4950 :     q = createPQExpBuffer();
   17463        4950 :     delq = createPQExpBuffer();
   17464             : 
   17465        4950 :     qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
   17466        4950 :     qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
   17467             : 
   17468             :     /*
   17469             :      * If there's an associated constraint, don't dump the index per se, but
   17470             :      * do dump any comment for it.  (This is safe because dependency ordering
   17471             :      * will have ensured the constraint is emitted first.)  Note that the
   17472             :      * emitted comment has to be shown as depending on the constraint, not the
   17473             :      * index, in such cases.
   17474             :      */
   17475        4950 :     if (!is_constraint)
   17476             :     {
   17477        2088 :         char       *indstatcols = indxinfo->indstatcols;
   17478        2088 :         char       *indstatvals = indxinfo->indstatvals;
   17479        2088 :         char      **indstatcolsarray = NULL;
   17480        2088 :         char      **indstatvalsarray = NULL;
   17481        2088 :         int         nstatcols = 0;
   17482        2088 :         int         nstatvals = 0;
   17483             : 
   17484        2088 :         if (dopt->binary_upgrade)
   17485         310 :             binary_upgrade_set_pg_class_oids(fout, q,
   17486             :                                              indxinfo->dobj.catId.oid);
   17487             : 
   17488             :         /* Plain secondary index */
   17489        2088 :         appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
   17490             : 
   17491             :         /*
   17492             :          * Append ALTER TABLE commands as needed to set properties that we
   17493             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17494             :          * similar code in dumpConstraint!
   17495             :          */
   17496             : 
   17497             :         /* If the index is clustered, we need to record that. */
   17498        2088 :         if (indxinfo->indisclustered)
   17499             :         {
   17500           0 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17501           0 :                               fmtQualifiedDumpable(tbinfo));
   17502             :             /* index name is not qualified in this syntax */
   17503           0 :             appendPQExpBuffer(q, " ON %s;\n",
   17504             :                               qindxname);
   17505             :         }
   17506             : 
   17507             :         /*
   17508             :          * If the index has any statistics on some of its columns, generate
   17509             :          * the associated ALTER INDEX queries.
   17510             :          */
   17511        2088 :         if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
   17512             :         {
   17513             :             int         j;
   17514             : 
   17515          68 :             if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
   17516           0 :                 pg_fatal("could not parse index statistic columns");
   17517          68 :             if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
   17518           0 :                 pg_fatal("could not parse index statistic values");
   17519          68 :             if (nstatcols != nstatvals)
   17520           0 :                 pg_fatal("mismatched number of columns and values for index statistics");
   17521             : 
   17522         204 :             for (j = 0; j < nstatcols; j++)
   17523             :             {
   17524         136 :                 appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
   17525             : 
   17526             :                 /*
   17527             :                  * Note that this is a column number, so no quotes should be
   17528             :                  * used.
   17529             :                  */
   17530         136 :                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
   17531         136 :                                   indstatcolsarray[j]);
   17532         136 :                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
   17533         136 :                                   indstatvalsarray[j]);
   17534             :             }
   17535             :         }
   17536             : 
   17537             :         /* Indexes can depend on extensions */
   17538        2088 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17539             :                                     "pg_catalog.pg_class",
   17540             :                                     "INDEX", qqindxname);
   17541             : 
   17542             :         /* If the index defines identity, we need to record that. */
   17543        2088 :         if (indxinfo->indisreplident)
   17544             :         {
   17545           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17546           0 :                               fmtQualifiedDumpable(tbinfo));
   17547             :             /* index name is not qualified in this syntax */
   17548           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17549             :                               qindxname);
   17550             :         }
   17551             : 
   17552        2088 :         appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
   17553             : 
   17554        2088 :         if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17555        2088 :             ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
   17556        2088 :                          ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
   17557             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17558             :                                       .tablespace = indxinfo->tablespace,
   17559             :                                       .owner = tbinfo->rolname,
   17560             :                                       .description = "INDEX",
   17561             :                                       .section = SECTION_POST_DATA,
   17562             :                                       .createStmt = q->data,
   17563             :                                       .dropStmt = delq->data));
   17564             : 
   17565        2088 :         free(indstatcolsarray);
   17566        2088 :         free(indstatvalsarray);
   17567             :     }
   17568             : 
   17569             :     /* Dump Index Comments */
   17570        4950 :     if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17571          30 :         dumpComment(fout, "INDEX", qindxname,
   17572          30 :                     tbinfo->dobj.namespace->dobj.name,
   17573             :                     tbinfo->rolname,
   17574             :                     indxinfo->dobj.catId, 0,
   17575             :                     is_constraint ? indxinfo->indexconstraint :
   17576             :                     indxinfo->dobj.dumpId);
   17577             : 
   17578        4950 :     destroyPQExpBuffer(q);
   17579        4950 :     destroyPQExpBuffer(delq);
   17580        4950 :     free(qindxname);
   17581        4950 :     free(qqindxname);
   17582             : }
   17583             : 
   17584             : /*
   17585             :  * dumpIndexAttach
   17586             :  *    write out to fout a partitioned-index attachment clause
   17587             :  */
   17588             : static void
   17589        1160 : dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
   17590             : {
   17591             :     /* Do nothing if not dumping schema */
   17592        1160 :     if (!fout->dopt->dumpSchema)
   17593          96 :         return;
   17594             : 
   17595        1064 :     if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17596             :     {
   17597        1064 :         PQExpBuffer q = createPQExpBuffer();
   17598             : 
   17599        1064 :         appendPQExpBuffer(q, "ALTER INDEX %s ",
   17600        1064 :                           fmtQualifiedDumpable(attachinfo->parentIdx));
   17601        1064 :         appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
   17602        1064 :                           fmtQualifiedDumpable(attachinfo->partitionIdx));
   17603             : 
   17604             :         /*
   17605             :          * There is no point in creating a drop query as the drop is done by
   17606             :          * index drop.  (If you think to change this, see also
   17607             :          * _printTocEntry().)  Although this object doesn't really have
   17608             :          * ownership as such, set the owner field anyway to ensure that the
   17609             :          * command is run by the correct role at restore time.
   17610             :          */
   17611        1064 :         ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
   17612        1064 :                      ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
   17613             :                                   .namespace = attachinfo->dobj.namespace->dobj.name,
   17614             :                                   .owner = attachinfo->parentIdx->indextable->rolname,
   17615             :                                   .description = "INDEX ATTACH",
   17616             :                                   .section = SECTION_POST_DATA,
   17617             :                                   .createStmt = q->data));
   17618             : 
   17619        1064 :         destroyPQExpBuffer(q);
   17620             :     }
   17621             : }
   17622             : 
   17623             : /*
   17624             :  * dumpStatisticsExt
   17625             :  *    write out to fout an extended statistics object
   17626             :  */
   17627             : static void
   17628         278 : dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
   17629             : {
   17630         278 :     DumpOptions *dopt = fout->dopt;
   17631             :     PQExpBuffer q;
   17632             :     PQExpBuffer delq;
   17633             :     PQExpBuffer query;
   17634             :     char       *qstatsextname;
   17635             :     PGresult   *res;
   17636             :     char       *stxdef;
   17637             : 
   17638             :     /* Do nothing if not dumping schema */
   17639         278 :     if (!dopt->dumpSchema)
   17640          36 :         return;
   17641             : 
   17642         242 :     q = createPQExpBuffer();
   17643         242 :     delq = createPQExpBuffer();
   17644         242 :     query = createPQExpBuffer();
   17645             : 
   17646         242 :     qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
   17647             : 
   17648         242 :     appendPQExpBuffer(query, "SELECT "
   17649             :                       "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
   17650             :                       statsextinfo->dobj.catId.oid);
   17651             : 
   17652         242 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   17653             : 
   17654         242 :     stxdef = PQgetvalue(res, 0, 0);
   17655             : 
   17656             :     /* Result of pg_get_statisticsobjdef is complete except for semicolon */
   17657         242 :     appendPQExpBuffer(q, "%s;\n", stxdef);
   17658             : 
   17659             :     /*
   17660             :      * We only issue an ALTER STATISTICS statement if the stxstattarget entry
   17661             :      * for this statistics object is not the default value.
   17662             :      */
   17663         242 :     if (statsextinfo->stattarget >= 0)
   17664             :     {
   17665          68 :         appendPQExpBuffer(q, "ALTER STATISTICS %s ",
   17666          68 :                           fmtQualifiedDumpable(statsextinfo));
   17667          68 :         appendPQExpBuffer(q, "SET STATISTICS %d;\n",
   17668             :                           statsextinfo->stattarget);
   17669             :     }
   17670             : 
   17671         242 :     appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
   17672         242 :                       fmtQualifiedDumpable(statsextinfo));
   17673             : 
   17674         242 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17675         242 :         ArchiveEntry(fout, statsextinfo->dobj.catId,
   17676             :                      statsextinfo->dobj.dumpId,
   17677         242 :                      ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
   17678             :                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
   17679             :                                   .owner = statsextinfo->rolname,
   17680             :                                   .description = "STATISTICS",
   17681             :                                   .section = SECTION_POST_DATA,
   17682             :                                   .createStmt = q->data,
   17683             :                                   .dropStmt = delq->data));
   17684             : 
   17685             :     /* Dump Statistics Comments */
   17686         242 :     if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17687           0 :         dumpComment(fout, "STATISTICS", qstatsextname,
   17688           0 :                     statsextinfo->dobj.namespace->dobj.name,
   17689             :                     statsextinfo->rolname,
   17690             :                     statsextinfo->dobj.catId, 0,
   17691             :                     statsextinfo->dobj.dumpId);
   17692             : 
   17693         242 :     PQclear(res);
   17694         242 :     destroyPQExpBuffer(q);
   17695         242 :     destroyPQExpBuffer(delq);
   17696         242 :     destroyPQExpBuffer(query);
   17697         242 :     free(qstatsextname);
   17698             : }
   17699             : 
   17700             : /*
   17701             :  * dumpConstraint
   17702             :  *    write out to fout a user-defined constraint
   17703             :  */
   17704             : static void
   17705        4756 : dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
   17706             : {
   17707        4756 :     DumpOptions *dopt = fout->dopt;
   17708        4756 :     TableInfo  *tbinfo = coninfo->contable;
   17709             :     PQExpBuffer q;
   17710             :     PQExpBuffer delq;
   17711        4756 :     char       *tag = NULL;
   17712             :     char       *foreign;
   17713             : 
   17714             :     /* Do nothing if not dumping schema */
   17715        4756 :     if (!dopt->dumpSchema)
   17716         184 :         return;
   17717             : 
   17718        4572 :     q = createPQExpBuffer();
   17719        4572 :     delq = createPQExpBuffer();
   17720             : 
   17721        8956 :     foreign = tbinfo &&
   17722        4572 :         tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
   17723             : 
   17724        4572 :     if (coninfo->contype == 'p' ||
   17725        2192 :         coninfo->contype == 'u' ||
   17726        1730 :         coninfo->contype == 'x')
   17727        2862 :     {
   17728             :         /* Index-related constraint */
   17729             :         IndxInfo   *indxinfo;
   17730             :         int         k;
   17731             : 
   17732        2862 :         indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
   17733             : 
   17734        2862 :         if (indxinfo == NULL)
   17735           0 :             pg_fatal("missing index for constraint \"%s\"",
   17736             :                      coninfo->dobj.name);
   17737             : 
   17738        2862 :         if (dopt->binary_upgrade)
   17739         286 :             binary_upgrade_set_pg_class_oids(fout, q,
   17740             :                                              indxinfo->dobj.catId.oid);
   17741             : 
   17742        2862 :         appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
   17743        2862 :                           fmtQualifiedDumpable(tbinfo));
   17744        2862 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
   17745        2862 :                           fmtId(coninfo->dobj.name));
   17746             : 
   17747        2862 :         if (coninfo->condef)
   17748             :         {
   17749             :             /* pg_get_constraintdef should have provided everything */
   17750          20 :             appendPQExpBuffer(q, "%s;\n", coninfo->condef);
   17751             :         }
   17752             :         else
   17753             :         {
   17754        2842 :             appendPQExpBufferStr(q,
   17755        2842 :                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
   17756             : 
   17757             :             /*
   17758             :              * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
   17759             :              * indexes. Being able to create this was fixed, but we need to
   17760             :              * make the index distinct in order to be able to restore the
   17761             :              * dump.
   17762             :              */
   17763        2842 :             if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
   17764           0 :                 appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
   17765        2842 :             appendPQExpBufferStr(q, " (");
   17766        6886 :             for (k = 0; k < indxinfo->indnkeyattrs; k++)
   17767             :             {
   17768        4044 :                 int         indkey = (int) indxinfo->indkeys[k];
   17769             :                 const char *attname;
   17770             : 
   17771        4044 :                 if (indkey == InvalidAttrNumber)
   17772           0 :                     break;
   17773        4044 :                 attname = getAttrName(indkey, tbinfo);
   17774             : 
   17775        4044 :                 appendPQExpBuffer(q, "%s%s",
   17776             :                                   (k == 0) ? "" : ", ",
   17777             :                                   fmtId(attname));
   17778             :             }
   17779        2842 :             if (coninfo->conperiod)
   17780         216 :                 appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
   17781             : 
   17782        2842 :             if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
   17783          40 :                 appendPQExpBufferStr(q, ") INCLUDE (");
   17784             : 
   17785        2922 :             for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
   17786             :             {
   17787          80 :                 int         indkey = (int) indxinfo->indkeys[k];
   17788             :                 const char *attname;
   17789             : 
   17790          80 :                 if (indkey == InvalidAttrNumber)
   17791           0 :                     break;
   17792          80 :                 attname = getAttrName(indkey, tbinfo);
   17793             : 
   17794         160 :                 appendPQExpBuffer(q, "%s%s",
   17795          80 :                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
   17796             :                                   fmtId(attname));
   17797             :             }
   17798             : 
   17799        2842 :             appendPQExpBufferChar(q, ')');
   17800             : 
   17801        2842 :             if (nonemptyReloptions(indxinfo->indreloptions))
   17802             :             {
   17803           0 :                 appendPQExpBufferStr(q, " WITH (");
   17804           0 :                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
   17805           0 :                 appendPQExpBufferChar(q, ')');
   17806             :             }
   17807             : 
   17808        2842 :             if (coninfo->condeferrable)
   17809             :             {
   17810          50 :                 appendPQExpBufferStr(q, " DEFERRABLE");
   17811          50 :                 if (coninfo->condeferred)
   17812          30 :                     appendPQExpBufferStr(q, " INITIALLY DEFERRED");
   17813             :             }
   17814             : 
   17815        2842 :             appendPQExpBufferStr(q, ";\n");
   17816             :         }
   17817             : 
   17818             :         /*
   17819             :          * Append ALTER TABLE commands as needed to set properties that we
   17820             :          * only have ALTER TABLE syntax for.  Keep this in sync with the
   17821             :          * similar code in dumpIndex!
   17822             :          */
   17823             : 
   17824             :         /* If the index is clustered, we need to record that. */
   17825        2862 :         if (indxinfo->indisclustered)
   17826             :         {
   17827          68 :             appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
   17828          68 :                               fmtQualifiedDumpable(tbinfo));
   17829             :             /* index name is not qualified in this syntax */
   17830          68 :             appendPQExpBuffer(q, " ON %s;\n",
   17831          68 :                               fmtId(indxinfo->dobj.name));
   17832             :         }
   17833             : 
   17834             :         /* If the index defines identity, we need to record that. */
   17835        2862 :         if (indxinfo->indisreplident)
   17836             :         {
   17837           0 :             appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
   17838           0 :                               fmtQualifiedDumpable(tbinfo));
   17839             :             /* index name is not qualified in this syntax */
   17840           0 :             appendPQExpBuffer(q, " INDEX %s;\n",
   17841           0 :                               fmtId(indxinfo->dobj.name));
   17842             :         }
   17843             : 
   17844             :         /* Indexes can depend on extensions */
   17845        2862 :         append_depends_on_extension(fout, q, &indxinfo->dobj,
   17846             :                                     "pg_catalog.pg_class", "INDEX",
   17847        2862 :                                     fmtQualifiedDumpable(indxinfo));
   17848             : 
   17849        2862 :         appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
   17850        2862 :                           fmtQualifiedDumpable(tbinfo));
   17851        2862 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17852        2862 :                           fmtId(coninfo->dobj.name));
   17853             : 
   17854        2862 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17855             : 
   17856        2862 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17857        2862 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17858        2862 :                          ARCHIVE_OPTS(.tag = tag,
   17859             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17860             :                                       .tablespace = indxinfo->tablespace,
   17861             :                                       .owner = tbinfo->rolname,
   17862             :                                       .description = "CONSTRAINT",
   17863             :                                       .section = SECTION_POST_DATA,
   17864             :                                       .createStmt = q->data,
   17865             :                                       .dropStmt = delq->data));
   17866             :     }
   17867        1710 :     else if (coninfo->contype == 'f')
   17868             :     {
   17869             :         char       *only;
   17870             : 
   17871             :         /*
   17872             :          * Foreign keys on partitioned tables are always declared as
   17873             :          * inheriting to partitions; for all other cases, emit them as
   17874             :          * applying ONLY directly to the named table, because that's how they
   17875             :          * work for regular inherited tables.
   17876             :          */
   17877         336 :         only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
   17878             : 
   17879             :         /*
   17880             :          * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
   17881             :          * current table data is not processed
   17882             :          */
   17883         336 :         appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
   17884         336 :                           only, fmtQualifiedDumpable(tbinfo));
   17885         336 :         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17886         336 :                           fmtId(coninfo->dobj.name),
   17887             :                           coninfo->condef);
   17888             : 
   17889         336 :         appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
   17890         336 :                           only, fmtQualifiedDumpable(tbinfo));
   17891         336 :         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17892         336 :                           fmtId(coninfo->dobj.name));
   17893             : 
   17894         336 :         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17895             : 
   17896         336 :         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17897         336 :             ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17898         336 :                          ARCHIVE_OPTS(.tag = tag,
   17899             :                                       .namespace = tbinfo->dobj.namespace->dobj.name,
   17900             :                                       .owner = tbinfo->rolname,
   17901             :                                       .description = "FK CONSTRAINT",
   17902             :                                       .section = SECTION_POST_DATA,
   17903             :                                       .createStmt = q->data,
   17904             :                                       .dropStmt = delq->data));
   17905             :     }
   17906        1374 :     else if (coninfo->contype == 'c' && tbinfo)
   17907             :     {
   17908             :         /* CHECK constraint on a table */
   17909             : 
   17910             :         /* Ignore if not to be dumped separately, or if it was inherited */
   17911        1186 :         if (coninfo->separate && coninfo->conislocal)
   17912             :         {
   17913             :             /* not ONLY since we want it to propagate to children */
   17914          90 :             appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
   17915          90 :                               fmtQualifiedDumpable(tbinfo));
   17916          90 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17917          90 :                               fmtId(coninfo->dobj.name),
   17918             :                               coninfo->condef);
   17919             : 
   17920          90 :             appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
   17921          90 :                               fmtQualifiedDumpable(tbinfo));
   17922          90 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17923          90 :                               fmtId(coninfo->dobj.name));
   17924             : 
   17925          90 :             tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
   17926             : 
   17927          90 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17928          90 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17929          90 :                              ARCHIVE_OPTS(.tag = tag,
   17930             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   17931             :                                           .owner = tbinfo->rolname,
   17932             :                                           .description = "CHECK CONSTRAINT",
   17933             :                                           .section = SECTION_POST_DATA,
   17934             :                                           .createStmt = q->data,
   17935             :                                           .dropStmt = delq->data));
   17936             :         }
   17937             :     }
   17938         188 :     else if (coninfo->contype == 'c' && tbinfo == NULL)
   17939         188 :     {
   17940             :         /* CHECK constraint on a domain */
   17941         188 :         TypeInfo   *tyinfo = coninfo->condomain;
   17942             : 
   17943             :         /* Ignore if not to be dumped separately */
   17944         188 :         if (coninfo->separate)
   17945             :         {
   17946           0 :             appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
   17947           0 :                               fmtQualifiedDumpable(tyinfo));
   17948           0 :             appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
   17949           0 :                               fmtId(coninfo->dobj.name),
   17950             :                               coninfo->condef);
   17951             : 
   17952           0 :             appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
   17953           0 :                               fmtQualifiedDumpable(tyinfo));
   17954           0 :             appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
   17955           0 :                               fmtId(coninfo->dobj.name));
   17956             : 
   17957           0 :             tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
   17958             : 
   17959           0 :             if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   17960           0 :                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
   17961           0 :                              ARCHIVE_OPTS(.tag = tag,
   17962             :                                           .namespace = tyinfo->dobj.namespace->dobj.name,
   17963             :                                           .owner = tyinfo->rolname,
   17964             :                                           .description = "CHECK CONSTRAINT",
   17965             :                                           .section = SECTION_POST_DATA,
   17966             :                                           .createStmt = q->data,
   17967             :                                           .dropStmt = delq->data));
   17968             :         }
   17969             :     }
   17970             :     else
   17971             :     {
   17972           0 :         pg_fatal("unrecognized constraint type: %c",
   17973             :                  coninfo->contype);
   17974             :     }
   17975             : 
   17976             :     /* Dump Constraint Comments --- only works for table constraints */
   17977        4572 :     if (tbinfo && coninfo->separate &&
   17978        3338 :         coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   17979          20 :         dumpTableConstraintComment(fout, coninfo);
   17980             : 
   17981        4572 :     free(tag);
   17982        4572 :     destroyPQExpBuffer(q);
   17983        4572 :     destroyPQExpBuffer(delq);
   17984             : }
   17985             : 
   17986             : /*
   17987             :  * dumpTableConstraintComment --- dump a constraint's comment if any
   17988             :  *
   17989             :  * This is split out because we need the function in two different places
   17990             :  * depending on whether the constraint is dumped as part of CREATE TABLE
   17991             :  * or as a separate ALTER command.
   17992             :  */
   17993             : static void
   17994          98 : dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
   17995             : {
   17996          98 :     TableInfo  *tbinfo = coninfo->contable;
   17997          98 :     PQExpBuffer conprefix = createPQExpBuffer();
   17998             :     char       *qtabname;
   17999             : 
   18000          98 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18001             : 
   18002          98 :     appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
   18003          98 :                       fmtId(coninfo->dobj.name));
   18004             : 
   18005          98 :     if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18006          98 :         dumpComment(fout, conprefix->data, qtabname,
   18007          98 :                     tbinfo->dobj.namespace->dobj.name,
   18008             :                     tbinfo->rolname,
   18009             :                     coninfo->dobj.catId, 0,
   18010          98 :                     coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
   18011             : 
   18012          98 :     destroyPQExpBuffer(conprefix);
   18013          98 :     free(qtabname);
   18014          98 : }
   18015             : 
   18016             : static inline SeqType
   18017        1278 : parse_sequence_type(const char *name)
   18018             : {
   18019        2844 :     for (int i = 0; i < lengthof(SeqTypeNames); i++)
   18020             :     {
   18021        2844 :         if (strcmp(SeqTypeNames[i], name) == 0)
   18022        1278 :             return (SeqType) i;
   18023             :     }
   18024             : 
   18025           0 :     pg_fatal("unrecognized sequence type: %s", name);
   18026             :     return (SeqType) 0;         /* keep compiler quiet */
   18027             : }
   18028             : 
   18029             : /*
   18030             :  * bsearch() comparator for SequenceItem
   18031             :  */
   18032             : static int
   18033        5930 : SequenceItemCmp(const void *p1, const void *p2)
   18034             : {
   18035        5930 :     SequenceItem v1 = *((const SequenceItem *) p1);
   18036        5930 :     SequenceItem v2 = *((const SequenceItem *) p2);
   18037             : 
   18038        5930 :     return pg_cmp_u32(v1.oid, v2.oid);
   18039             : }
   18040             : 
   18041             : /*
   18042             :  * collectSequences
   18043             :  *
   18044             :  * Construct a table of sequence information.  This table is sorted by OID for
   18045             :  * speed in lookup.
   18046             :  */
   18047             : static void
   18048         320 : collectSequences(Archive *fout)
   18049             : {
   18050             :     PGresult   *res;
   18051             :     const char *query;
   18052             : 
   18053             :     /*
   18054             :      * Before Postgres 10, sequence metadata is in the sequence itself.  With
   18055             :      * some extra effort, we might be able to use the sorted table for those
   18056             :      * versions, but for now it seems unlikely to be worth it.
   18057             :      *
   18058             :      * Since version 18, we can gather the sequence data in this query with
   18059             :      * pg_get_sequence_data(), but we only do so for non-schema-only dumps.
   18060             :      */
   18061         320 :     if (fout->remoteVersion < 100000)
   18062           0 :         return;
   18063         320 :     else if (fout->remoteVersion < 180000 ||
   18064         320 :              (!fout->dopt->dumpData && !fout->dopt->sequence_data))
   18065           8 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18066             :             "seqstart, seqincrement, "
   18067             :             "seqmax, seqmin, "
   18068             :             "seqcache, seqcycle, "
   18069             :             "NULL, 'f' "
   18070             :             "FROM pg_catalog.pg_sequence "
   18071             :             "ORDER BY seqrelid";
   18072             :     else
   18073         312 :         query = "SELECT seqrelid, format_type(seqtypid, NULL), "
   18074             :             "seqstart, seqincrement, "
   18075             :             "seqmax, seqmin, "
   18076             :             "seqcache, seqcycle, "
   18077             :             "last_value, is_called "
   18078             :             "FROM pg_catalog.pg_sequence, "
   18079             :             "pg_get_sequence_data(seqrelid) "
   18080             :             "ORDER BY seqrelid;";
   18081             : 
   18082         320 :     res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
   18083             : 
   18084         320 :     nsequences = PQntuples(res);
   18085         320 :     sequences = (SequenceItem *) pg_malloc(nsequences * sizeof(SequenceItem));
   18086             : 
   18087        1598 :     for (int i = 0; i < nsequences; i++)
   18088             :     {
   18089        1278 :         sequences[i].oid = atooid(PQgetvalue(res, i, 0));
   18090        1278 :         sequences[i].seqtype = parse_sequence_type(PQgetvalue(res, i, 1));
   18091        1278 :         sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
   18092        1278 :         sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
   18093        1278 :         sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
   18094        1278 :         sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
   18095        1278 :         sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
   18096        1278 :         sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
   18097        1278 :         sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
   18098        1278 :         sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
   18099             :     }
   18100             : 
   18101         320 :     PQclear(res);
   18102             : }
   18103             : 
   18104             : /*
   18105             :  * dumpSequence
   18106             :  *    write the declaration (not data) of one user-defined sequence
   18107             :  */
   18108             : static void
   18109         752 : dumpSequence(Archive *fout, const TableInfo *tbinfo)
   18110             : {
   18111         752 :     DumpOptions *dopt = fout->dopt;
   18112             :     SequenceItem *seq;
   18113             :     bool        is_ascending;
   18114             :     int64       default_minv,
   18115             :                 default_maxv;
   18116         752 :     PQExpBuffer query = createPQExpBuffer();
   18117         752 :     PQExpBuffer delqry = createPQExpBuffer();
   18118             :     char       *qseqname;
   18119         752 :     TableInfo  *owning_tab = NULL;
   18120             : 
   18121         752 :     qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
   18122             : 
   18123             :     /*
   18124             :      * For versions >= 10, the sequence information is gathered in a sorted
   18125             :      * table before any calls to dumpSequence().  See collectSequences() for
   18126             :      * more information.
   18127             :      */
   18128         752 :     if (fout->remoteVersion >= 100000)
   18129             :     {
   18130         752 :         SequenceItem key = {0};
   18131             : 
   18132             :         Assert(sequences);
   18133             : 
   18134         752 :         key.oid = tbinfo->dobj.catId.oid;
   18135         752 :         seq = bsearch(&key, sequences, nsequences,
   18136             :                       sizeof(SequenceItem), SequenceItemCmp);
   18137             :     }
   18138             :     else
   18139             :     {
   18140             :         PGresult   *res;
   18141             : 
   18142             :         /*
   18143             :          * Before PostgreSQL 10, sequence metadata is in the sequence itself.
   18144             :          *
   18145             :          * Note: it might seem that 'bigint' potentially needs to be
   18146             :          * schema-qualified, but actually that's a keyword.
   18147             :          */
   18148           0 :         appendPQExpBuffer(query,
   18149             :                           "SELECT 'bigint' AS sequence_type, "
   18150             :                           "start_value, increment_by, max_value, min_value, "
   18151             :                           "cache_value, is_cycled FROM %s",
   18152           0 :                           fmtQualifiedDumpable(tbinfo));
   18153             : 
   18154           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18155             : 
   18156           0 :         if (PQntuples(res) != 1)
   18157           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   18158             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   18159             :                               PQntuples(res)),
   18160             :                      tbinfo->dobj.name, PQntuples(res));
   18161             : 
   18162           0 :         seq = pg_malloc0(sizeof(SequenceItem));
   18163           0 :         seq->seqtype = parse_sequence_type(PQgetvalue(res, 0, 0));
   18164           0 :         seq->startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
   18165           0 :         seq->incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
   18166           0 :         seq->maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
   18167           0 :         seq->minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
   18168           0 :         seq->cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
   18169           0 :         seq->cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
   18170             : 
   18171           0 :         PQclear(res);
   18172             :     }
   18173             : 
   18174             :     /* Calculate default limits for a sequence of this type */
   18175         752 :     is_ascending = (seq->incby >= 0);
   18176         752 :     if (seq->seqtype == SEQTYPE_SMALLINT)
   18177             :     {
   18178          50 :         default_minv = is_ascending ? 1 : PG_INT16_MIN;
   18179          50 :         default_maxv = is_ascending ? PG_INT16_MAX : -1;
   18180             :     }
   18181         702 :     else if (seq->seqtype == SEQTYPE_INTEGER)
   18182             :     {
   18183         580 :         default_minv = is_ascending ? 1 : PG_INT32_MIN;
   18184         580 :         default_maxv = is_ascending ? PG_INT32_MAX : -1;
   18185             :     }
   18186         122 :     else if (seq->seqtype == SEQTYPE_BIGINT)
   18187             :     {
   18188         122 :         default_minv = is_ascending ? 1 : PG_INT64_MIN;
   18189         122 :         default_maxv = is_ascending ? PG_INT64_MAX : -1;
   18190             :     }
   18191             :     else
   18192             :     {
   18193           0 :         pg_fatal("unrecognized sequence type: %d", seq->seqtype);
   18194             :         default_minv = default_maxv = 0;    /* keep compiler quiet */
   18195             :     }
   18196             : 
   18197             :     /*
   18198             :      * Identity sequences are not to be dropped separately.
   18199             :      */
   18200         752 :     if (!tbinfo->is_identity_sequence)
   18201             :     {
   18202         464 :         appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
   18203         464 :                           fmtQualifiedDumpable(tbinfo));
   18204             :     }
   18205             : 
   18206         752 :     resetPQExpBuffer(query);
   18207             : 
   18208         752 :     if (dopt->binary_upgrade)
   18209             :     {
   18210         122 :         binary_upgrade_set_pg_class_oids(fout, query,
   18211             :                                          tbinfo->dobj.catId.oid);
   18212             : 
   18213             :         /*
   18214             :          * In older PG versions a sequence will have a pg_type entry, but v14
   18215             :          * and up don't use that, so don't attempt to preserve the type OID.
   18216             :          */
   18217             :     }
   18218             : 
   18219         752 :     if (tbinfo->is_identity_sequence)
   18220             :     {
   18221         288 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   18222             : 
   18223         288 :         appendPQExpBuffer(query,
   18224             :                           "ALTER TABLE %s ",
   18225         288 :                           fmtQualifiedDumpable(owning_tab));
   18226         288 :         appendPQExpBuffer(query,
   18227             :                           "ALTER COLUMN %s ADD GENERATED ",
   18228         288 :                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   18229         288 :         if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
   18230         208 :             appendPQExpBufferStr(query, "ALWAYS");
   18231          80 :         else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
   18232          80 :             appendPQExpBufferStr(query, "BY DEFAULT");
   18233         288 :         appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
   18234         288 :                           fmtQualifiedDumpable(tbinfo));
   18235             : 
   18236             :         /*
   18237             :          * Emit persistence option only if it's different from the owning
   18238             :          * table's.  This avoids using this new syntax unnecessarily.
   18239             :          */
   18240         288 :         if (tbinfo->relpersistence != owning_tab->relpersistence)
   18241          20 :             appendPQExpBuffer(query, "    %s\n",
   18242          20 :                               tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   18243             :                               "UNLOGGED" : "LOGGED");
   18244             :     }
   18245             :     else
   18246             :     {
   18247         464 :         appendPQExpBuffer(query,
   18248             :                           "CREATE %sSEQUENCE %s\n",
   18249         464 :                           tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
   18250             :                           "UNLOGGED " : "",
   18251         464 :                           fmtQualifiedDumpable(tbinfo));
   18252             : 
   18253         464 :         if (seq->seqtype != SEQTYPE_BIGINT)
   18254         372 :             appendPQExpBuffer(query, "    AS %s\n", SeqTypeNames[seq->seqtype]);
   18255             :     }
   18256             : 
   18257         752 :     appendPQExpBuffer(query, "    START WITH " INT64_FORMAT "\n", seq->startv);
   18258             : 
   18259         752 :     appendPQExpBuffer(query, "    INCREMENT BY " INT64_FORMAT "\n", seq->incby);
   18260             : 
   18261         752 :     if (seq->minv != default_minv)
   18262          30 :         appendPQExpBuffer(query, "    MINVALUE " INT64_FORMAT "\n", seq->minv);
   18263             :     else
   18264         722 :         appendPQExpBufferStr(query, "    NO MINVALUE\n");
   18265             : 
   18266         752 :     if (seq->maxv != default_maxv)
   18267          30 :         appendPQExpBuffer(query, "    MAXVALUE " INT64_FORMAT "\n", seq->maxv);
   18268             :     else
   18269         722 :         appendPQExpBufferStr(query, "    NO MAXVALUE\n");
   18270             : 
   18271         752 :     appendPQExpBuffer(query,
   18272             :                       "    CACHE " INT64_FORMAT "%s",
   18273         752 :                       seq->cache, (seq->cycled ? "\n    CYCLE" : ""));
   18274             : 
   18275         752 :     if (tbinfo->is_identity_sequence)
   18276         288 :         appendPQExpBufferStr(query, "\n);\n");
   18277             :     else
   18278         464 :         appendPQExpBufferStr(query, ";\n");
   18279             : 
   18280             :     /* binary_upgrade:  no need to clear TOAST table oid */
   18281             : 
   18282         752 :     if (dopt->binary_upgrade)
   18283         122 :         binary_upgrade_extension_member(query, &tbinfo->dobj,
   18284             :                                         "SEQUENCE", qseqname,
   18285         122 :                                         tbinfo->dobj.namespace->dobj.name);
   18286             : 
   18287         752 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18288         752 :         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
   18289         752 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18290             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18291             :                                   .owner = tbinfo->rolname,
   18292             :                                   .description = "SEQUENCE",
   18293             :                                   .section = SECTION_PRE_DATA,
   18294             :                                   .createStmt = query->data,
   18295             :                                   .dropStmt = delqry->data));
   18296             : 
   18297             :     /*
   18298             :      * If the sequence is owned by a table column, emit the ALTER for it as a
   18299             :      * separate TOC entry immediately following the sequence's own entry. It's
   18300             :      * OK to do this rather than using full sorting logic, because the
   18301             :      * dependency that tells us it's owned will have forced the table to be
   18302             :      * created first.  We can't just include the ALTER in the TOC entry
   18303             :      * because it will fail if we haven't reassigned the sequence owner to
   18304             :      * match the table's owner.
   18305             :      *
   18306             :      * We need not schema-qualify the table reference because both sequence
   18307             :      * and table must be in the same schema.
   18308             :      */
   18309         752 :     if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
   18310             :     {
   18311         282 :         owning_tab = findTableByOid(tbinfo->owning_tab);
   18312             : 
   18313         282 :         if (owning_tab == NULL)
   18314           0 :             pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
   18315             :                      tbinfo->owning_tab, tbinfo->dobj.catId.oid);
   18316             : 
   18317         282 :         if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18318             :         {
   18319         278 :             resetPQExpBuffer(query);
   18320         278 :             appendPQExpBuffer(query, "ALTER SEQUENCE %s",
   18321         278 :                               fmtQualifiedDumpable(tbinfo));
   18322         278 :             appendPQExpBuffer(query, " OWNED BY %s",
   18323         278 :                               fmtQualifiedDumpable(owning_tab));
   18324         278 :             appendPQExpBuffer(query, ".%s;\n",
   18325         278 :                               fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
   18326             : 
   18327         278 :             if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18328         278 :                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18329         278 :                              ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18330             :                                           .namespace = tbinfo->dobj.namespace->dobj.name,
   18331             :                                           .owner = tbinfo->rolname,
   18332             :                                           .description = "SEQUENCE OWNED BY",
   18333             :                                           .section = SECTION_PRE_DATA,
   18334             :                                           .createStmt = query->data,
   18335             :                                           .deps = &(tbinfo->dobj.dumpId),
   18336             :                                           .nDeps = 1));
   18337             :         }
   18338             :     }
   18339             : 
   18340             :     /* Dump Sequence Comments and Security Labels */
   18341         752 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18342           0 :         dumpComment(fout, "SEQUENCE", qseqname,
   18343           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   18344             :                     tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   18345             : 
   18346         752 :     if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
   18347           0 :         dumpSecLabel(fout, "SEQUENCE", qseqname,
   18348           0 :                      tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   18349             :                      tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
   18350             : 
   18351         752 :     if (fout->remoteVersion < 100000)
   18352           0 :         pg_free(seq);
   18353         752 :     destroyPQExpBuffer(query);
   18354         752 :     destroyPQExpBuffer(delqry);
   18355         752 :     free(qseqname);
   18356         752 : }
   18357             : 
   18358             : /*
   18359             :  * dumpSequenceData
   18360             :  *    write the data of one user-defined sequence
   18361             :  */
   18362             : static void
   18363         790 : dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
   18364             : {
   18365         790 :     TableInfo  *tbinfo = tdinfo->tdtable;
   18366             :     int64       last;
   18367             :     bool        called;
   18368         790 :     PQExpBuffer query = createPQExpBuffer();
   18369             : 
   18370             :     /*
   18371             :      * For versions >= 18, the sequence information is gathered in the sorted
   18372             :      * array before any calls to dumpSequenceData().  See collectSequences()
   18373             :      * for more information.
   18374             :      *
   18375             :      * For older versions, we have to query the sequence relations
   18376             :      * individually.
   18377             :      */
   18378         790 :     if (fout->remoteVersion < 180000)
   18379             :     {
   18380             :         PGresult   *res;
   18381             : 
   18382           0 :         appendPQExpBuffer(query,
   18383             :                           "SELECT last_value, is_called FROM %s",
   18384           0 :                           fmtQualifiedDumpable(tbinfo));
   18385             : 
   18386           0 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18387             : 
   18388           0 :         if (PQntuples(res) != 1)
   18389           0 :             pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
   18390             :                               "query to get data of sequence \"%s\" returned %d rows (expected 1)",
   18391             :                               PQntuples(res)),
   18392             :                      tbinfo->dobj.name, PQntuples(res));
   18393             : 
   18394           0 :         last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
   18395           0 :         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
   18396             : 
   18397           0 :         PQclear(res);
   18398             :     }
   18399             :     else
   18400             :     {
   18401         790 :         SequenceItem key = {0};
   18402             :         SequenceItem *entry;
   18403             : 
   18404             :         Assert(sequences);
   18405             :         Assert(tbinfo->dobj.catId.oid);
   18406             : 
   18407         790 :         key.oid = tbinfo->dobj.catId.oid;
   18408         790 :         entry = bsearch(&key, sequences, nsequences,
   18409             :                         sizeof(SequenceItem), SequenceItemCmp);
   18410             : 
   18411         790 :         last = entry->last_value;
   18412         790 :         called = entry->is_called;
   18413             :     }
   18414             : 
   18415         790 :     resetPQExpBuffer(query);
   18416         790 :     appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
   18417         790 :     appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
   18418         790 :     appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
   18419             :                       last, (called ? "true" : "false"));
   18420             : 
   18421         790 :     if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
   18422         790 :         ArchiveEntry(fout, nilCatalogId, createDumpId(),
   18423         790 :                      ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
   18424             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18425             :                                   .owner = tbinfo->rolname,
   18426             :                                   .description = "SEQUENCE SET",
   18427             :                                   .section = SECTION_DATA,
   18428             :                                   .createStmt = query->data,
   18429             :                                   .deps = &(tbinfo->dobj.dumpId),
   18430             :                                   .nDeps = 1));
   18431             : 
   18432         790 :     destroyPQExpBuffer(query);
   18433         790 : }
   18434             : 
   18435             : /*
   18436             :  * dumpTrigger
   18437             :  *    write the declaration of one user-defined table trigger
   18438             :  */
   18439             : static void
   18440        1066 : dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
   18441             : {
   18442        1066 :     DumpOptions *dopt = fout->dopt;
   18443        1066 :     TableInfo  *tbinfo = tginfo->tgtable;
   18444             :     PQExpBuffer query;
   18445             :     PQExpBuffer delqry;
   18446             :     PQExpBuffer trigprefix;
   18447             :     PQExpBuffer trigidentity;
   18448             :     char       *qtabname;
   18449             :     char       *tag;
   18450             : 
   18451             :     /* Do nothing if not dumping schema */
   18452        1066 :     if (!dopt->dumpSchema)
   18453          62 :         return;
   18454             : 
   18455        1004 :     query = createPQExpBuffer();
   18456        1004 :     delqry = createPQExpBuffer();
   18457        1004 :     trigprefix = createPQExpBuffer();
   18458        1004 :     trigidentity = createPQExpBuffer();
   18459             : 
   18460        1004 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18461             : 
   18462        1004 :     appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
   18463        1004 :     appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
   18464             : 
   18465        1004 :     appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
   18466        1004 :     appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
   18467             : 
   18468             :     /* Triggers can depend on extensions */
   18469        1004 :     append_depends_on_extension(fout, query, &tginfo->dobj,
   18470             :                                 "pg_catalog.pg_trigger", "TRIGGER",
   18471        1004 :                                 trigidentity->data);
   18472             : 
   18473        1004 :     if (tginfo->tgispartition)
   18474             :     {
   18475             :         Assert(tbinfo->ispartition);
   18476             : 
   18477             :         /*
   18478             :          * Partition triggers only appear here because their 'tgenabled' flag
   18479             :          * differs from its parent's.  The trigger is created already, so
   18480             :          * remove the CREATE and replace it with an ALTER.  (Clear out the
   18481             :          * DROP query too, so that pg_dump --create does not cause errors.)
   18482             :          */
   18483         230 :         resetPQExpBuffer(query);
   18484         230 :         resetPQExpBuffer(delqry);
   18485         230 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   18486         230 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   18487         230 :                           fmtQualifiedDumpable(tbinfo));
   18488         230 :         switch (tginfo->tgenabled)
   18489             :         {
   18490          80 :             case 'f':
   18491             :             case 'D':
   18492          80 :                 appendPQExpBufferStr(query, "DISABLE");
   18493          80 :                 break;
   18494           0 :             case 't':
   18495             :             case 'O':
   18496           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18497           0 :                 break;
   18498          70 :             case 'R':
   18499          70 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18500          70 :                 break;
   18501          80 :             case 'A':
   18502          80 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18503          80 :                 break;
   18504             :         }
   18505         230 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   18506         230 :                           fmtId(tginfo->dobj.name));
   18507             :     }
   18508         774 :     else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
   18509             :     {
   18510           0 :         appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
   18511           0 :                           tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
   18512           0 :                           fmtQualifiedDumpable(tbinfo));
   18513           0 :         switch (tginfo->tgenabled)
   18514             :         {
   18515           0 :             case 'D':
   18516             :             case 'f':
   18517           0 :                 appendPQExpBufferStr(query, "DISABLE");
   18518           0 :                 break;
   18519           0 :             case 'A':
   18520           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18521           0 :                 break;
   18522           0 :             case 'R':
   18523           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18524           0 :                 break;
   18525           0 :             default:
   18526           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18527           0 :                 break;
   18528             :         }
   18529           0 :         appendPQExpBuffer(query, " TRIGGER %s;\n",
   18530           0 :                           fmtId(tginfo->dobj.name));
   18531             :     }
   18532             : 
   18533        1004 :     appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
   18534        1004 :                       fmtId(tginfo->dobj.name));
   18535             : 
   18536        1004 :     tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
   18537             : 
   18538        1004 :     if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18539        1004 :         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
   18540        1004 :                      ARCHIVE_OPTS(.tag = tag,
   18541             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18542             :                                   .owner = tbinfo->rolname,
   18543             :                                   .description = "TRIGGER",
   18544             :                                   .section = SECTION_POST_DATA,
   18545             :                                   .createStmt = query->data,
   18546             :                                   .dropStmt = delqry->data));
   18547             : 
   18548        1004 :     if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18549           0 :         dumpComment(fout, trigprefix->data, qtabname,
   18550           0 :                     tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
   18551             :                     tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
   18552             : 
   18553        1004 :     free(tag);
   18554        1004 :     destroyPQExpBuffer(query);
   18555        1004 :     destroyPQExpBuffer(delqry);
   18556        1004 :     destroyPQExpBuffer(trigprefix);
   18557        1004 :     destroyPQExpBuffer(trigidentity);
   18558        1004 :     free(qtabname);
   18559             : }
   18560             : 
   18561             : /*
   18562             :  * dumpEventTrigger
   18563             :  *    write the declaration of one user-defined event trigger
   18564             :  */
   18565             : static void
   18566          88 : dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
   18567             : {
   18568          88 :     DumpOptions *dopt = fout->dopt;
   18569             :     PQExpBuffer query;
   18570             :     PQExpBuffer delqry;
   18571             :     char       *qevtname;
   18572             : 
   18573             :     /* Do nothing if not dumping schema */
   18574          88 :     if (!dopt->dumpSchema)
   18575          12 :         return;
   18576             : 
   18577          76 :     query = createPQExpBuffer();
   18578          76 :     delqry = createPQExpBuffer();
   18579             : 
   18580          76 :     qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
   18581             : 
   18582          76 :     appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
   18583          76 :     appendPQExpBufferStr(query, qevtname);
   18584          76 :     appendPQExpBufferStr(query, " ON ");
   18585          76 :     appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
   18586             : 
   18587          76 :     if (strcmp("", evtinfo->evttags) != 0)
   18588             :     {
   18589          10 :         appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
   18590          10 :         appendPQExpBufferStr(query, evtinfo->evttags);
   18591          10 :         appendPQExpBufferChar(query, ')');
   18592             :     }
   18593             : 
   18594          76 :     appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
   18595          76 :     appendPQExpBufferStr(query, evtinfo->evtfname);
   18596          76 :     appendPQExpBufferStr(query, "();\n");
   18597             : 
   18598          76 :     if (evtinfo->evtenabled != 'O')
   18599             :     {
   18600           0 :         appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
   18601             :                           qevtname);
   18602           0 :         switch (evtinfo->evtenabled)
   18603             :         {
   18604           0 :             case 'D':
   18605           0 :                 appendPQExpBufferStr(query, "DISABLE");
   18606           0 :                 break;
   18607           0 :             case 'A':
   18608           0 :                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
   18609           0 :                 break;
   18610           0 :             case 'R':
   18611           0 :                 appendPQExpBufferStr(query, "ENABLE REPLICA");
   18612           0 :                 break;
   18613           0 :             default:
   18614           0 :                 appendPQExpBufferStr(query, "ENABLE");
   18615           0 :                 break;
   18616             :         }
   18617           0 :         appendPQExpBufferStr(query, ";\n");
   18618             :     }
   18619             : 
   18620          76 :     appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
   18621             :                       qevtname);
   18622             : 
   18623          76 :     if (dopt->binary_upgrade)
   18624           4 :         binary_upgrade_extension_member(query, &evtinfo->dobj,
   18625             :                                         "EVENT TRIGGER", qevtname, NULL);
   18626             : 
   18627          76 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18628          76 :         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
   18629          76 :                      ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
   18630             :                                   .owner = evtinfo->evtowner,
   18631             :                                   .description = "EVENT TRIGGER",
   18632             :                                   .section = SECTION_POST_DATA,
   18633             :                                   .createStmt = query->data,
   18634             :                                   .dropStmt = delqry->data));
   18635             : 
   18636          76 :     if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18637           0 :         dumpComment(fout, "EVENT TRIGGER", qevtname,
   18638             :                     NULL, evtinfo->evtowner,
   18639             :                     evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
   18640             : 
   18641          76 :     destroyPQExpBuffer(query);
   18642          76 :     destroyPQExpBuffer(delqry);
   18643          76 :     free(qevtname);
   18644             : }
   18645             : 
   18646             : /*
   18647             :  * dumpRule
   18648             :  *      Dump a rule
   18649             :  */
   18650             : static void
   18651        2330 : dumpRule(Archive *fout, const RuleInfo *rinfo)
   18652             : {
   18653        2330 :     DumpOptions *dopt = fout->dopt;
   18654        2330 :     TableInfo  *tbinfo = rinfo->ruletable;
   18655             :     bool        is_view;
   18656             :     PQExpBuffer query;
   18657             :     PQExpBuffer cmd;
   18658             :     PQExpBuffer delcmd;
   18659             :     PQExpBuffer ruleprefix;
   18660             :     char       *qtabname;
   18661             :     PGresult   *res;
   18662             :     char       *tag;
   18663             : 
   18664             :     /* Do nothing if not dumping schema */
   18665        2330 :     if (!dopt->dumpSchema)
   18666         132 :         return;
   18667             : 
   18668             :     /*
   18669             :      * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
   18670             :      * we do not want to dump it as a separate object.
   18671             :      */
   18672        2198 :     if (!rinfo->separate)
   18673        1776 :         return;
   18674             : 
   18675             :     /*
   18676             :      * If it's an ON SELECT rule, we want to print it as a view definition,
   18677             :      * instead of a rule.
   18678             :      */
   18679         422 :     is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
   18680             : 
   18681         422 :     query = createPQExpBuffer();
   18682         422 :     cmd = createPQExpBuffer();
   18683         422 :     delcmd = createPQExpBuffer();
   18684         422 :     ruleprefix = createPQExpBuffer();
   18685             : 
   18686         422 :     qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
   18687             : 
   18688         422 :     if (is_view)
   18689             :     {
   18690             :         PQExpBuffer result;
   18691             : 
   18692             :         /*
   18693             :          * We need OR REPLACE here because we'll be replacing a dummy view.
   18694             :          * Otherwise this should look largely like the regular view dump code.
   18695             :          */
   18696          20 :         appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
   18697          20 :                           fmtQualifiedDumpable(tbinfo));
   18698          20 :         if (nonemptyReloptions(tbinfo->reloptions))
   18699             :         {
   18700           0 :             appendPQExpBufferStr(cmd, " WITH (");
   18701           0 :             appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
   18702           0 :             appendPQExpBufferChar(cmd, ')');
   18703             :         }
   18704          20 :         result = createViewAsClause(fout, tbinfo);
   18705          20 :         appendPQExpBuffer(cmd, " AS\n%s", result->data);
   18706          20 :         destroyPQExpBuffer(result);
   18707          20 :         if (tbinfo->checkoption != NULL)
   18708           0 :             appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
   18709             :                               tbinfo->checkoption);
   18710          20 :         appendPQExpBufferStr(cmd, ";\n");
   18711             :     }
   18712             :     else
   18713             :     {
   18714             :         /* In the rule case, just print pg_get_ruledef's result verbatim */
   18715         402 :         appendPQExpBuffer(query,
   18716             :                           "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
   18717             :                           rinfo->dobj.catId.oid);
   18718             : 
   18719         402 :         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18720             : 
   18721         402 :         if (PQntuples(res) != 1)
   18722           0 :             pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
   18723             :                      rinfo->dobj.name, tbinfo->dobj.name);
   18724             : 
   18725         402 :         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
   18726             : 
   18727         402 :         PQclear(res);
   18728             :     }
   18729             : 
   18730             :     /*
   18731             :      * Add the command to alter the rules replication firing semantics if it
   18732             :      * differs from the default.
   18733             :      */
   18734         422 :     if (rinfo->ev_enabled != 'O')
   18735             :     {
   18736          30 :         appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
   18737          30 :         switch (rinfo->ev_enabled)
   18738             :         {
   18739           0 :             case 'A':
   18740           0 :                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
   18741           0 :                                   fmtId(rinfo->dobj.name));
   18742           0 :                 break;
   18743           0 :             case 'R':
   18744           0 :                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
   18745           0 :                                   fmtId(rinfo->dobj.name));
   18746           0 :                 break;
   18747          30 :             case 'D':
   18748          30 :                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
   18749          30 :                                   fmtId(rinfo->dobj.name));
   18750          30 :                 break;
   18751             :         }
   18752         392 :     }
   18753             : 
   18754         422 :     if (is_view)
   18755             :     {
   18756             :         /*
   18757             :          * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
   18758             :          * REPLACE VIEW to replace the rule with something with minimal
   18759             :          * dependencies.
   18760             :          */
   18761             :         PQExpBuffer result;
   18762             : 
   18763          20 :         appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
   18764          20 :                           fmtQualifiedDumpable(tbinfo));
   18765          20 :         result = createDummyViewAsClause(fout, tbinfo);
   18766          20 :         appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
   18767          20 :         destroyPQExpBuffer(result);
   18768             :     }
   18769             :     else
   18770             :     {
   18771         402 :         appendPQExpBuffer(delcmd, "DROP RULE %s ",
   18772         402 :                           fmtId(rinfo->dobj.name));
   18773         402 :         appendPQExpBuffer(delcmd, "ON %s;\n",
   18774         402 :                           fmtQualifiedDumpable(tbinfo));
   18775             :     }
   18776             : 
   18777         422 :     appendPQExpBuffer(ruleprefix, "RULE %s ON",
   18778         422 :                       fmtId(rinfo->dobj.name));
   18779             : 
   18780         422 :     tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
   18781             : 
   18782         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
   18783         422 :         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
   18784         422 :                      ARCHIVE_OPTS(.tag = tag,
   18785             :                                   .namespace = tbinfo->dobj.namespace->dobj.name,
   18786             :                                   .owner = tbinfo->rolname,
   18787             :                                   .description = "RULE",
   18788             :                                   .section = SECTION_POST_DATA,
   18789             :                                   .createStmt = cmd->data,
   18790             :                                   .dropStmt = delcmd->data));
   18791             : 
   18792             :     /* Dump rule comments */
   18793         422 :     if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
   18794           0 :         dumpComment(fout, ruleprefix->data, qtabname,
   18795           0 :                     tbinfo->dobj.namespace->dobj.name,
   18796             :                     tbinfo->rolname,
   18797             :                     rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
   18798             : 
   18799         422 :     free(tag);
   18800         422 :     destroyPQExpBuffer(query);
   18801         422 :     destroyPQExpBuffer(cmd);
   18802         422 :     destroyPQExpBuffer(delcmd);
   18803         422 :     destroyPQExpBuffer(ruleprefix);
   18804         422 :     free(qtabname);
   18805             : }
   18806             : 
   18807             : /*
   18808             :  * getExtensionMembership --- obtain extension membership data
   18809             :  *
   18810             :  * We need to identify objects that are extension members as soon as they're
   18811             :  * loaded, so that we can correctly determine whether they need to be dumped.
   18812             :  * Generally speaking, extension member objects will get marked as *not* to
   18813             :  * be dumped, as they will be recreated by the single CREATE EXTENSION
   18814             :  * command.  However, in binary upgrade mode we still need to dump the members
   18815             :  * individually.
   18816             :  */
   18817             : void
   18818         322 : getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
   18819             :                        int numExtensions)
   18820             : {
   18821             :     PQExpBuffer query;
   18822             :     PGresult   *res;
   18823             :     int         ntups,
   18824             :                 i;
   18825             :     int         i_classid,
   18826             :                 i_objid,
   18827             :                 i_refobjid;
   18828             :     ExtensionInfo *ext;
   18829             : 
   18830             :     /* Nothing to do if no extensions */
   18831         322 :     if (numExtensions == 0)
   18832           0 :         return;
   18833             : 
   18834         322 :     query = createPQExpBuffer();
   18835             : 
   18836             :     /* refclassid constraint is redundant but may speed the search */
   18837         322 :     appendPQExpBufferStr(query, "SELECT "
   18838             :                          "classid, objid, refobjid "
   18839             :                          "FROM pg_depend "
   18840             :                          "WHERE refclassid = 'pg_extension'::regclass "
   18841             :                          "AND deptype = 'e' "
   18842             :                          "ORDER BY 3");
   18843             : 
   18844         322 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   18845             : 
   18846         322 :     ntups = PQntuples(res);
   18847             : 
   18848         322 :     i_classid = PQfnumber(res, "classid");
   18849         322 :     i_objid = PQfnumber(res, "objid");
   18850         322 :     i_refobjid = PQfnumber(res, "refobjid");
   18851             : 
   18852             :     /*
   18853             :      * Since we ordered the SELECT by referenced ID, we can expect that
   18854             :      * multiple entries for the same extension will appear together; this
   18855             :      * saves on searches.
   18856             :      */
   18857         322 :     ext = NULL;
   18858             : 
   18859        2810 :     for (i = 0; i < ntups; i++)
   18860             :     {
   18861             :         CatalogId   objId;
   18862             :         Oid         extId;
   18863             : 
   18864        2488 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   18865        2488 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   18866        2488 :         extId = atooid(PQgetvalue(res, i, i_refobjid));
   18867             : 
   18868        2488 :         if (ext == NULL ||
   18869        2166 :             ext->dobj.catId.oid != extId)
   18870         372 :             ext = findExtensionByOid(extId);
   18871             : 
   18872        2488 :         if (ext == NULL)
   18873             :         {
   18874             :             /* shouldn't happen */
   18875           0 :             pg_log_warning("could not find referenced extension %u", extId);
   18876           0 :             continue;
   18877             :         }
   18878             : 
   18879        2488 :         recordExtensionMembership(objId, ext);
   18880             :     }
   18881             : 
   18882         322 :     PQclear(res);
   18883             : 
   18884         322 :     destroyPQExpBuffer(query);
   18885             : }
   18886             : 
   18887             : /*
   18888             :  * processExtensionTables --- deal with extension configuration tables
   18889             :  *
   18890             :  * There are two parts to this process:
   18891             :  *
   18892             :  * 1. Identify and create dump records for extension configuration tables.
   18893             :  *
   18894             :  *    Extensions can mark tables as "configuration", which means that the user
   18895             :  *    is able and expected to modify those tables after the extension has been
   18896             :  *    loaded.  For these tables, we dump out only the data- the structure is
   18897             :  *    expected to be handled at CREATE EXTENSION time, including any indexes or
   18898             :  *    foreign keys, which brings us to-
   18899             :  *
   18900             :  * 2. Record FK dependencies between configuration tables.
   18901             :  *
   18902             :  *    Due to the FKs being created at CREATE EXTENSION time and therefore before
   18903             :  *    the data is loaded, we have to work out what the best order for reloading
   18904             :  *    the data is, to avoid FK violations when the tables are restored.  This is
   18905             :  *    not perfect- we can't handle circular dependencies and if any exist they
   18906             :  *    will cause an invalid dump to be produced (though at least all of the data
   18907             :  *    is included for a user to manually restore).  This is currently documented
   18908             :  *    but perhaps we can provide a better solution in the future.
   18909             :  */
   18910             : void
   18911         320 : processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
   18912             :                        int numExtensions)
   18913             : {
   18914         320 :     DumpOptions *dopt = fout->dopt;
   18915             :     PQExpBuffer query;
   18916             :     PGresult   *res;
   18917             :     int         ntups,
   18918             :                 i;
   18919             :     int         i_conrelid,
   18920             :                 i_confrelid;
   18921             : 
   18922             :     /* Nothing to do if no extensions */
   18923         320 :     if (numExtensions == 0)
   18924           0 :         return;
   18925             : 
   18926             :     /*
   18927             :      * Identify extension configuration tables and create TableDataInfo
   18928             :      * objects for them, ensuring their data will be dumped even though the
   18929             :      * tables themselves won't be.
   18930             :      *
   18931             :      * Note that we create TableDataInfo objects even in schema-only mode, ie,
   18932             :      * user data in a configuration table is treated like schema data. This
   18933             :      * seems appropriate since system data in a config table would get
   18934             :      * reloaded by CREATE EXTENSION.  If the extension is not listed in the
   18935             :      * list of extensions to be included, none of its data is dumped.
   18936             :      */
   18937         690 :     for (i = 0; i < numExtensions; i++)
   18938             :     {
   18939         370 :         ExtensionInfo *curext = &(extinfo[i]);
   18940         370 :         char       *extconfig = curext->extconfig;
   18941         370 :         char       *extcondition = curext->extcondition;
   18942         370 :         char      **extconfigarray = NULL;
   18943         370 :         char      **extconditionarray = NULL;
   18944         370 :         int         nconfigitems = 0;
   18945         370 :         int         nconditionitems = 0;
   18946             : 
   18947             :         /*
   18948             :          * Check if this extension is listed as to include in the dump.  If
   18949             :          * not, any table data associated with it is discarded.
   18950             :          */
   18951         370 :         if (extension_include_oids.head != NULL &&
   18952          16 :             !simple_oid_list_member(&extension_include_oids,
   18953             :                                     curext->dobj.catId.oid))
   18954          12 :             continue;
   18955             : 
   18956             :         /*
   18957             :          * Check if this extension is listed as to exclude in the dump.  If
   18958             :          * yes, any table data associated with it is discarded.
   18959             :          */
   18960         370 :         if (extension_exclude_oids.head != NULL &&
   18961           8 :             simple_oid_list_member(&extension_exclude_oids,
   18962             :                                    curext->dobj.catId.oid))
   18963           4 :             continue;
   18964             : 
   18965         358 :         if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
   18966             :         {
   18967             :             int         j;
   18968             : 
   18969          40 :             if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
   18970           0 :                 pg_fatal("could not parse %s array", "extconfig");
   18971          40 :             if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
   18972           0 :                 pg_fatal("could not parse %s array", "extcondition");
   18973          40 :             if (nconfigitems != nconditionitems)
   18974           0 :                 pg_fatal("mismatched number of configurations and conditions for extension");
   18975             : 
   18976         120 :             for (j = 0; j < nconfigitems; j++)
   18977             :             {
   18978             :                 TableInfo  *configtbl;
   18979          80 :                 Oid         configtbloid = atooid(extconfigarray[j]);
   18980          80 :                 bool        dumpobj =
   18981          80 :                     curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
   18982             : 
   18983          80 :                 configtbl = findTableByOid(configtbloid);
   18984          80 :                 if (configtbl == NULL)
   18985           0 :                     continue;
   18986             : 
   18987             :                 /*
   18988             :                  * Tables of not-to-be-dumped extensions shouldn't be dumped
   18989             :                  * unless the table or its schema is explicitly included
   18990             :                  */
   18991          80 :                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
   18992             :                 {
   18993             :                     /* check table explicitly requested */
   18994           4 :                     if (table_include_oids.head != NULL &&
   18995           0 :                         simple_oid_list_member(&table_include_oids,
   18996             :                                                configtbloid))
   18997           0 :                         dumpobj = true;
   18998             : 
   18999             :                     /* check table's schema explicitly requested */
   19000           4 :                     if (configtbl->dobj.namespace->dobj.dump &
   19001             :                         DUMP_COMPONENT_DATA)
   19002           4 :                         dumpobj = true;
   19003             :                 }
   19004             : 
   19005             :                 /* check table excluded by an exclusion switch */
   19006          88 :                 if (table_exclude_oids.head != NULL &&
   19007           8 :                     simple_oid_list_member(&table_exclude_oids,
   19008             :                                            configtbloid))
   19009           2 :                     dumpobj = false;
   19010             : 
   19011             :                 /* check schema excluded by an exclusion switch */
   19012          80 :                 if (simple_oid_list_member(&schema_exclude_oids,
   19013          80 :                                            configtbl->dobj.namespace->dobj.catId.oid))
   19014           0 :                     dumpobj = false;
   19015             : 
   19016          80 :                 if (dumpobj)
   19017             :                 {
   19018          78 :                     makeTableDataInfo(dopt, configtbl);
   19019          78 :                     if (configtbl->dataObj != NULL)
   19020             :                     {
   19021          78 :                         if (strlen(extconditionarray[j]) > 0)
   19022           0 :                             configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
   19023             :                     }
   19024             :                 }
   19025             :             }
   19026             :         }
   19027         358 :         if (extconfigarray)
   19028          40 :             free(extconfigarray);
   19029         358 :         if (extconditionarray)
   19030          40 :             free(extconditionarray);
   19031             :     }
   19032             : 
   19033             :     /*
   19034             :      * Now that all the TableDataInfo objects have been created for all the
   19035             :      * extensions, check their FK dependencies and register them to try and
   19036             :      * dump the data out in an order that they can be restored in.
   19037             :      *
   19038             :      * Note that this is not a problem for user tables as their FKs are
   19039             :      * recreated after the data has been loaded.
   19040             :      */
   19041             : 
   19042         320 :     query = createPQExpBuffer();
   19043             : 
   19044         320 :     printfPQExpBuffer(query,
   19045             :                       "SELECT conrelid, confrelid "
   19046             :                       "FROM pg_constraint "
   19047             :                       "JOIN pg_depend ON (objid = confrelid) "
   19048             :                       "WHERE contype = 'f' "
   19049             :                       "AND refclassid = 'pg_extension'::regclass "
   19050             :                       "AND classid = 'pg_class'::regclass;");
   19051             : 
   19052         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19053         320 :     ntups = PQntuples(res);
   19054             : 
   19055         320 :     i_conrelid = PQfnumber(res, "conrelid");
   19056         320 :     i_confrelid = PQfnumber(res, "confrelid");
   19057             : 
   19058             :     /* Now get the dependencies and register them */
   19059         320 :     for (i = 0; i < ntups; i++)
   19060             :     {
   19061             :         Oid         conrelid,
   19062             :                     confrelid;
   19063             :         TableInfo  *reftable,
   19064             :                    *contable;
   19065             : 
   19066           0 :         conrelid = atooid(PQgetvalue(res, i, i_conrelid));
   19067           0 :         confrelid = atooid(PQgetvalue(res, i, i_confrelid));
   19068           0 :         contable = findTableByOid(conrelid);
   19069           0 :         reftable = findTableByOid(confrelid);
   19070             : 
   19071           0 :         if (reftable == NULL ||
   19072           0 :             reftable->dataObj == NULL ||
   19073           0 :             contable == NULL ||
   19074           0 :             contable->dataObj == NULL)
   19075           0 :             continue;
   19076             : 
   19077             :         /*
   19078             :          * Make referencing TABLE_DATA object depend on the referenced table's
   19079             :          * TABLE_DATA object.
   19080             :          */
   19081           0 :         addObjectDependency(&contable->dataObj->dobj,
   19082           0 :                             reftable->dataObj->dobj.dumpId);
   19083             :     }
   19084         320 :     PQclear(res);
   19085         320 :     destroyPQExpBuffer(query);
   19086             : }
   19087             : 
   19088             : /*
   19089             :  * getDependencies --- obtain available dependency data
   19090             :  */
   19091             : static void
   19092         320 : getDependencies(Archive *fout)
   19093             : {
   19094             :     PQExpBuffer query;
   19095             :     PGresult   *res;
   19096             :     int         ntups,
   19097             :                 i;
   19098             :     int         i_classid,
   19099             :                 i_objid,
   19100             :                 i_refclassid,
   19101             :                 i_refobjid,
   19102             :                 i_deptype;
   19103             :     DumpableObject *dobj,
   19104             :                *refdobj;
   19105             : 
   19106         320 :     pg_log_info("reading dependency data");
   19107             : 
   19108         320 :     query = createPQExpBuffer();
   19109             : 
   19110             :     /*
   19111             :      * Messy query to collect the dependency data we need.  Note that we
   19112             :      * ignore the sub-object column, so that dependencies of or on a column
   19113             :      * look the same as dependencies of or on a whole table.
   19114             :      *
   19115             :      * PIN dependencies aren't interesting, and EXTENSION dependencies were
   19116             :      * already processed by getExtensionMembership.
   19117             :      */
   19118         320 :     appendPQExpBufferStr(query, "SELECT "
   19119             :                          "classid, objid, refclassid, refobjid, deptype "
   19120             :                          "FROM pg_depend "
   19121             :                          "WHERE deptype != 'p' AND deptype != 'e'\n");
   19122             : 
   19123             :     /*
   19124             :      * Since we don't treat pg_amop entries as separate DumpableObjects, we
   19125             :      * have to translate their dependencies into dependencies of their parent
   19126             :      * opfamily.  Ignore internal dependencies though, as those will point to
   19127             :      * their parent opclass, which we needn't consider here (and if we did,
   19128             :      * it'd just result in circular dependencies).  Also, "loose" opfamily
   19129             :      * entries will have dependencies on their parent opfamily, which we
   19130             :      * should drop since they'd likewise become useless self-dependencies.
   19131             :      * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
   19132             :      */
   19133         320 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19134             :                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
   19135             :                          "FROM pg_depend d, pg_amop o "
   19136             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19137             :                          "classid = 'pg_amop'::regclass AND objid = o.oid "
   19138             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
   19139             : 
   19140             :     /* Likewise for pg_amproc entries */
   19141         320 :     appendPQExpBufferStr(query, "UNION ALL\n"
   19142             :                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
   19143             :                          "FROM pg_depend d, pg_amproc p "
   19144             :                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
   19145             :                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
   19146             :                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
   19147             : 
   19148             :     /* Sort the output for efficiency below */
   19149         320 :     appendPQExpBufferStr(query, "ORDER BY 1,2");
   19150             : 
   19151         320 :     res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
   19152             : 
   19153         320 :     ntups = PQntuples(res);
   19154             : 
   19155         320 :     i_classid = PQfnumber(res, "classid");
   19156         320 :     i_objid = PQfnumber(res, "objid");
   19157         320 :     i_refclassid = PQfnumber(res, "refclassid");
   19158         320 :     i_refobjid = PQfnumber(res, "refobjid");
   19159         320 :     i_deptype = PQfnumber(res, "deptype");
   19160             : 
   19161             :     /*
   19162             :      * Since we ordered the SELECT by referencing ID, we can expect that
   19163             :      * multiple entries for the same object will appear together; this saves
   19164             :      * on searches.
   19165             :      */
   19166         320 :     dobj = NULL;
   19167             : 
   19168      703938 :     for (i = 0; i < ntups; i++)
   19169             :     {
   19170             :         CatalogId   objId;
   19171             :         CatalogId   refobjId;
   19172             :         char        deptype;
   19173             : 
   19174      703618 :         objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
   19175      703618 :         objId.oid = atooid(PQgetvalue(res, i, i_objid));
   19176      703618 :         refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
   19177      703618 :         refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
   19178      703618 :         deptype = *(PQgetvalue(res, i, i_deptype));
   19179             : 
   19180      703618 :         if (dobj == NULL ||
   19181      655450 :             dobj->catId.tableoid != objId.tableoid ||
   19182      651568 :             dobj->catId.oid != objId.oid)
   19183      312302 :             dobj = findObjectByCatalogId(objId);
   19184             : 
   19185             :         /*
   19186             :          * Failure to find objects mentioned in pg_depend is not unexpected,
   19187             :          * since for example we don't collect info about TOAST tables.
   19188             :          */
   19189      703618 :         if (dobj == NULL)
   19190             :         {
   19191             : #ifdef NOT_USED
   19192             :             pg_log_warning("no referencing object %u %u",
   19193             :                            objId.tableoid, objId.oid);
   19194             : #endif
   19195       49416 :             continue;
   19196             :         }
   19197             : 
   19198      655770 :         refdobj = findObjectByCatalogId(refobjId);
   19199             : 
   19200      655770 :         if (refdobj == NULL)
   19201             :         {
   19202             : #ifdef NOT_USED
   19203             :             pg_log_warning("no referenced object %u %u",
   19204             :                            refobjId.tableoid, refobjId.oid);
   19205             : #endif
   19206        1568 :             continue;
   19207             :         }
   19208             : 
   19209             :         /*
   19210             :          * For 'x' dependencies, mark the object for later; we still add the
   19211             :          * normal dependency, for possible ordering purposes.  Currently
   19212             :          * pg_dump_sort.c knows to put extensions ahead of all object types
   19213             :          * that could possibly depend on them, but this is safer.
   19214             :          */
   19215      654202 :         if (deptype == 'x')
   19216          88 :             dobj->depends_on_ext = true;
   19217             : 
   19218             :         /*
   19219             :          * Ordinarily, table rowtypes have implicit dependencies on their
   19220             :          * tables.  However, for a composite type the implicit dependency goes
   19221             :          * the other way in pg_depend; which is the right thing for DROP but
   19222             :          * it doesn't produce the dependency ordering we need. So in that one
   19223             :          * case, we reverse the direction of the dependency.
   19224             :          */
   19225      654202 :         if (deptype == 'i' &&
   19226      182342 :             dobj->objType == DO_TABLE &&
   19227        2376 :             refdobj->objType == DO_TYPE)
   19228         368 :             addObjectDependency(refdobj, dobj->dumpId);
   19229             :         else
   19230             :             /* normal case */
   19231      653834 :             addObjectDependency(dobj, refdobj->dumpId);
   19232             :     }
   19233             : 
   19234         320 :     PQclear(res);
   19235             : 
   19236         320 :     destroyPQExpBuffer(query);
   19237         320 : }
   19238             : 
   19239             : 
   19240             : /*
   19241             :  * createBoundaryObjects - create dummy DumpableObjects to represent
   19242             :  * dump section boundaries.
   19243             :  */
   19244             : static DumpableObject *
   19245         320 : createBoundaryObjects(void)
   19246             : {
   19247             :     DumpableObject *dobjs;
   19248             : 
   19249         320 :     dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
   19250             : 
   19251         320 :     dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
   19252         320 :     dobjs[0].catId = nilCatalogId;
   19253         320 :     AssignDumpId(dobjs + 0);
   19254         320 :     dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
   19255             : 
   19256         320 :     dobjs[1].objType = DO_POST_DATA_BOUNDARY;
   19257         320 :     dobjs[1].catId = nilCatalogId;
   19258         320 :     AssignDumpId(dobjs + 1);
   19259         320 :     dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
   19260             : 
   19261         320 :     return dobjs;
   19262             : }
   19263             : 
   19264             : /*
   19265             :  * addBoundaryDependencies - add dependencies as needed to enforce the dump
   19266             :  * section boundaries.
   19267             :  */
   19268             : static void
   19269         320 : addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
   19270             :                         DumpableObject *boundaryObjs)
   19271             : {
   19272         320 :     DumpableObject *preDataBound = boundaryObjs + 0;
   19273         320 :     DumpableObject *postDataBound = boundaryObjs + 1;
   19274             :     int         i;
   19275             : 
   19276     1187560 :     for (i = 0; i < numObjs; i++)
   19277             :     {
   19278     1187240 :         DumpableObject *dobj = dobjs[i];
   19279             : 
   19280             :         /*
   19281             :          * The classification of object types here must match the SECTION_xxx
   19282             :          * values assigned during subsequent ArchiveEntry calls!
   19283             :          */
   19284     1187240 :         switch (dobj->objType)
   19285             :         {
   19286     1100808 :             case DO_NAMESPACE:
   19287             :             case DO_EXTENSION:
   19288             :             case DO_TYPE:
   19289             :             case DO_SHELL_TYPE:
   19290             :             case DO_FUNC:
   19291             :             case DO_AGG:
   19292             :             case DO_OPERATOR:
   19293             :             case DO_ACCESS_METHOD:
   19294             :             case DO_OPCLASS:
   19295             :             case DO_OPFAMILY:
   19296             :             case DO_COLLATION:
   19297             :             case DO_CONVERSION:
   19298             :             case DO_TABLE:
   19299             :             case DO_TABLE_ATTACH:
   19300             :             case DO_ATTRDEF:
   19301             :             case DO_PROCLANG:
   19302             :             case DO_CAST:
   19303             :             case DO_DUMMY_TYPE:
   19304             :             case DO_TSPARSER:
   19305             :             case DO_TSDICT:
   19306             :             case DO_TSTEMPLATE:
   19307             :             case DO_TSCONFIG:
   19308             :             case DO_FDW:
   19309             :             case DO_FOREIGN_SERVER:
   19310             :             case DO_TRANSFORM:
   19311             :                 /* Pre-data objects: must come before the pre-data boundary */
   19312     1100808 :                 addObjectDependency(preDataBound, dobj->dumpId);
   19313     1100808 :                 break;
   19314        8934 :             case DO_TABLE_DATA:
   19315             :             case DO_SEQUENCE_SET:
   19316             :             case DO_LARGE_OBJECT:
   19317             :             case DO_LARGE_OBJECT_DATA:
   19318             :                 /* Data objects: must come between the boundaries */
   19319        8934 :                 addObjectDependency(dobj, preDataBound->dumpId);
   19320        8934 :                 addObjectDependency(postDataBound, dobj->dumpId);
   19321        8934 :                 break;
   19322       11324 :             case DO_INDEX:
   19323             :             case DO_INDEX_ATTACH:
   19324             :             case DO_STATSEXT:
   19325             :             case DO_REFRESH_MATVIEW:
   19326             :             case DO_TRIGGER:
   19327             :             case DO_EVENT_TRIGGER:
   19328             :             case DO_DEFAULT_ACL:
   19329             :             case DO_POLICY:
   19330             :             case DO_PUBLICATION:
   19331             :             case DO_PUBLICATION_REL:
   19332             :             case DO_PUBLICATION_TABLE_IN_SCHEMA:
   19333             :             case DO_SUBSCRIPTION:
   19334             :             case DO_SUBSCRIPTION_REL:
   19335             :                 /* Post-data objects: must come after the post-data boundary */
   19336       11324 :                 addObjectDependency(dobj, postDataBound->dumpId);
   19337       11324 :                 break;
   19338       48792 :             case DO_RULE:
   19339             :                 /* Rules are post-data, but only if dumped separately */
   19340       48792 :                 if (((RuleInfo *) dobj)->separate)
   19341        1186 :                     addObjectDependency(dobj, postDataBound->dumpId);
   19342       48792 :                 break;
   19343        4844 :             case DO_CONSTRAINT:
   19344             :             case DO_FK_CONSTRAINT:
   19345             :                 /* Constraints are post-data, but only if dumped separately */
   19346        4844 :                 if (((ConstraintInfo *) dobj)->separate)
   19347        3510 :                     addObjectDependency(dobj, postDataBound->dumpId);
   19348        4844 :                 break;
   19349         320 :             case DO_PRE_DATA_BOUNDARY:
   19350             :                 /* nothing to do */
   19351         320 :                 break;
   19352         320 :             case DO_POST_DATA_BOUNDARY:
   19353             :                 /* must come after the pre-data boundary */
   19354         320 :                 addObjectDependency(dobj, preDataBound->dumpId);
   19355         320 :                 break;
   19356       11898 :             case DO_REL_STATS:
   19357             :                 /* stats section varies by parent object type, DATA or POST */
   19358       11898 :                 if (statisticsDumpSection((RelStatsInfo *) dobj) == SECTION_DATA)
   19359             :                 {
   19360        8008 :                     addObjectDependency(dobj, preDataBound->dumpId);
   19361        8008 :                     addObjectDependency(postDataBound, dobj->dumpId);
   19362             :                 }
   19363             :                 else
   19364        3890 :                     addObjectDependency(dobj, postDataBound->dumpId);
   19365       11898 :                 break;
   19366             :         }
   19367     1187240 :     }
   19368         320 : }
   19369             : 
   19370             : 
   19371             : /*
   19372             :  * BuildArchiveDependencies - create dependency data for archive TOC entries
   19373             :  *
   19374             :  * The raw dependency data obtained by getDependencies() is not terribly
   19375             :  * useful in an archive dump, because in many cases there are dependency
   19376             :  * chains linking through objects that don't appear explicitly in the dump.
   19377             :  * For example, a view will depend on its _RETURN rule while the _RETURN rule
   19378             :  * will depend on other objects --- but the rule will not appear as a separate
   19379             :  * object in the dump.  We need to adjust the view's dependencies to include
   19380             :  * whatever the rule depends on that is included in the dump.
   19381             :  *
   19382             :  * Just to make things more complicated, there are also "special" dependencies
   19383             :  * such as the dependency of a TABLE DATA item on its TABLE, which we must
   19384             :  * not rearrange because pg_restore knows that TABLE DATA only depends on
   19385             :  * its table.  In these cases we must leave the dependencies strictly as-is
   19386             :  * even if they refer to not-to-be-dumped objects.
   19387             :  *
   19388             :  * To handle this, the convention is that "special" dependencies are created
   19389             :  * during ArchiveEntry calls, and an archive TOC item that has any such
   19390             :  * entries will not be touched here.  Otherwise, we recursively search the
   19391             :  * DumpableObject data structures to build the correct dependencies for each
   19392             :  * archive TOC item.
   19393             :  */
   19394             : static void
   19395          66 : BuildArchiveDependencies(Archive *fout)
   19396             : {
   19397          66 :     ArchiveHandle *AH = (ArchiveHandle *) fout;
   19398             :     TocEntry   *te;
   19399             : 
   19400             :     /* Scan all TOC entries in the archive */
   19401       13322 :     for (te = AH->toc->next; te != AH->toc; te = te->next)
   19402             :     {
   19403             :         DumpableObject *dobj;
   19404             :         DumpId     *dependencies;
   19405             :         int         nDeps;
   19406             :         int         allocDeps;
   19407             : 
   19408             :         /* No need to process entries that will not be dumped */
   19409       13256 :         if (te->reqs == 0)
   19410        6310 :             continue;
   19411             :         /* Ignore entries that already have "special" dependencies */
   19412       13250 :         if (te->nDeps > 0)
   19413        5750 :             continue;
   19414             :         /* Otherwise, look up the item's original DumpableObject, if any */
   19415        7500 :         dobj = findObjectByDumpId(te->dumpId);
   19416        7500 :         if (dobj == NULL)
   19417         342 :             continue;
   19418             :         /* No work if it has no dependencies */
   19419        7158 :         if (dobj->nDeps <= 0)
   19420         212 :             continue;
   19421             :         /* Set up work array */
   19422        6946 :         allocDeps = 64;
   19423        6946 :         dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
   19424        6946 :         nDeps = 0;
   19425             :         /* Recursively find all dumpable dependencies */
   19426        6946 :         findDumpableDependencies(AH, dobj,
   19427             :                                  &dependencies, &nDeps, &allocDeps);
   19428             :         /* And save 'em ... */
   19429        6946 :         if (nDeps > 0)
   19430             :         {
   19431        5320 :             dependencies = (DumpId *) pg_realloc(dependencies,
   19432             :                                                  nDeps * sizeof(DumpId));
   19433        5320 :             te->dependencies = dependencies;
   19434        5320 :             te->nDeps = nDeps;
   19435             :         }
   19436             :         else
   19437        1626 :             free(dependencies);
   19438             :     }
   19439          66 : }
   19440             : 
   19441             : /* Recursive search subroutine for BuildArchiveDependencies */
   19442             : static void
   19443       17018 : findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
   19444             :                          DumpId **dependencies, int *nDeps, int *allocDeps)
   19445             : {
   19446             :     int         i;
   19447             : 
   19448             :     /*
   19449             :      * Ignore section boundary objects: if we search through them, we'll
   19450             :      * report lots of bogus dependencies.
   19451             :      */
   19452       17018 :     if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
   19453       16980 :         dobj->objType == DO_POST_DATA_BOUNDARY)
   19454        2996 :         return;
   19455             : 
   19456       35428 :     for (i = 0; i < dobj->nDeps; i++)
   19457             :     {
   19458       21406 :         DumpId      depid = dobj->dependencies[i];
   19459             : 
   19460       21406 :         if (TocIDRequired(AH, depid) != 0)
   19461             :         {
   19462             :             /* Object will be dumped, so just reference it as a dependency */
   19463       11334 :             if (*nDeps >= *allocDeps)
   19464             :             {
   19465           0 :                 *allocDeps *= 2;
   19466           0 :                 *dependencies = (DumpId *) pg_realloc(*dependencies,
   19467           0 :                                                       *allocDeps * sizeof(DumpId));
   19468             :             }
   19469       11334 :             (*dependencies)[*nDeps] = depid;
   19470       11334 :             (*nDeps)++;
   19471             :         }
   19472             :         else
   19473             :         {
   19474             :             /*
   19475             :              * Object will not be dumped, so recursively consider its deps. We
   19476             :              * rely on the assumption that sortDumpableObjects already broke
   19477             :              * any dependency loops, else we might recurse infinitely.
   19478             :              */
   19479       10072 :             DumpableObject *otherdobj = findObjectByDumpId(depid);
   19480             : 
   19481       10072 :             if (otherdobj)
   19482       10072 :                 findDumpableDependencies(AH, otherdobj,
   19483             :                                          dependencies, nDeps, allocDeps);
   19484             :         }
   19485             :     }
   19486             : }
   19487             : 
   19488             : 
   19489             : /*
   19490             :  * getFormattedTypeName - retrieve a nicely-formatted type name for the
   19491             :  * given type OID.
   19492             :  *
   19493             :  * This does not guarantee to schema-qualify the output, so it should not
   19494             :  * be used to create the target object name for CREATE or ALTER commands.
   19495             :  *
   19496             :  * Note that the result is cached and must not be freed by the caller.
   19497             :  */
   19498             : static const char *
   19499        4648 : getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
   19500             : {
   19501             :     TypeInfo   *typeInfo;
   19502             :     char       *result;
   19503             :     PQExpBuffer query;
   19504             :     PGresult   *res;
   19505             : 
   19506        4648 :     if (oid == 0)
   19507             :     {
   19508           0 :         if ((opts & zeroAsStar) != 0)
   19509           0 :             return "*";
   19510           0 :         else if ((opts & zeroAsNone) != 0)
   19511           0 :             return "NONE";
   19512             :     }
   19513             : 
   19514             :     /* see if we have the result cached in the type's TypeInfo record */
   19515        4648 :     typeInfo = findTypeByOid(oid);
   19516        4648 :     if (typeInfo && typeInfo->ftypname)
   19517        3686 :         return typeInfo->ftypname;
   19518             : 
   19519         962 :     query = createPQExpBuffer();
   19520         962 :     appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
   19521             :                       oid);
   19522             : 
   19523         962 :     res = ExecuteSqlQueryForSingleRow(fout, query->data);
   19524             : 
   19525             :     /* result of format_type is already quoted */
   19526         962 :     result = pg_strdup(PQgetvalue(res, 0, 0));
   19527             : 
   19528         962 :     PQclear(res);
   19529         962 :     destroyPQExpBuffer(query);
   19530             : 
   19531             :     /*
   19532             :      * Cache the result for re-use in later requests, if possible.  If we
   19533             :      * don't have a TypeInfo for the type, the string will be leaked once the
   19534             :      * caller is done with it ... but that case really should not happen, so
   19535             :      * leaking if it does seems acceptable.
   19536             :      */
   19537         962 :     if (typeInfo)
   19538         962 :         typeInfo->ftypname = result;
   19539             : 
   19540         962 :     return result;
   19541             : }
   19542             : 
   19543             : /*
   19544             :  * Return a column list clause for the given relation.
   19545             :  *
   19546             :  * Special case: if there are no undropped columns in the relation, return
   19547             :  * "", not an invalid "()" column list.
   19548             :  */
   19549             : static const char *
   19550       15248 : fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
   19551             : {
   19552       15248 :     int         numatts = ti->numatts;
   19553       15248 :     char      **attnames = ti->attnames;
   19554       15248 :     bool       *attisdropped = ti->attisdropped;
   19555       15248 :     char       *attgenerated = ti->attgenerated;
   19556             :     bool        needComma;
   19557             :     int         i;
   19558             : 
   19559       15248 :     appendPQExpBufferChar(buffer, '(');
   19560       15248 :     needComma = false;
   19561       76492 :     for (i = 0; i < numatts; i++)
   19562             :     {
   19563       61244 :         if (attisdropped[i])
   19564        1204 :             continue;
   19565       60040 :         if (attgenerated[i])
   19566        2160 :             continue;
   19567       57880 :         if (needComma)
   19568       43104 :             appendPQExpBufferStr(buffer, ", ");
   19569       57880 :         appendPQExpBufferStr(buffer, fmtId(attnames[i]));
   19570       57880 :         needComma = true;
   19571             :     }
   19572             : 
   19573       15248 :     if (!needComma)
   19574         472 :         return "";                /* no undropped columns */
   19575             : 
   19576       14776 :     appendPQExpBufferChar(buffer, ')');
   19577       14776 :     return buffer->data;
   19578             : }
   19579             : 
   19580             : /*
   19581             :  * Check if a reloptions array is nonempty.
   19582             :  */
   19583             : static bool
   19584       25822 : nonemptyReloptions(const char *reloptions)
   19585             : {
   19586             :     /* Don't want to print it if it's just "{}" */
   19587       25822 :     return (reloptions != NULL && strlen(reloptions) > 2);
   19588             : }
   19589             : 
   19590             : /*
   19591             :  * Format a reloptions array and append it to the given buffer.
   19592             :  *
   19593             :  * "prefix" is prepended to the option names; typically it's "" or "toast.".
   19594             :  */
   19595             : static void
   19596         424 : appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
   19597             :                         const char *prefix, Archive *fout)
   19598             : {
   19599             :     bool        res;
   19600             : 
   19601         424 :     res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
   19602         424 :                                 fout->std_strings);
   19603         424 :     if (!res)
   19604           0 :         pg_log_warning("could not parse %s array", "reloptions");
   19605         424 : }
   19606             : 
   19607             : /*
   19608             :  * read_dump_filters - retrieve object identifier patterns from file
   19609             :  *
   19610             :  * Parse the specified filter file for include and exclude patterns, and add
   19611             :  * them to the relevant lists.  If the filename is "-" then filters will be
   19612             :  * read from STDIN rather than a file.
   19613             :  */
   19614             : static void
   19615          52 : read_dump_filters(const char *filename, DumpOptions *dopt)
   19616             : {
   19617             :     FilterStateData fstate;
   19618             :     char       *objname;
   19619             :     FilterCommandType comtype;
   19620             :     FilterObjectType objtype;
   19621             : 
   19622          52 :     filter_init(&fstate, filename, exit_nicely);
   19623             : 
   19624         116 :     while (filter_read_item(&fstate, &objname, &comtype, &objtype))
   19625             :     {
   19626          66 :         if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
   19627             :         {
   19628          34 :             switch (objtype)
   19629             :             {
   19630           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19631           0 :                     break;
   19632           0 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19633             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19634             :                 case FILTER_OBJECT_TYPE_INDEX:
   19635             :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19636             :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19637             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19638           0 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19639             :                                         "include",
   19640             :                                         filter_object_type_name(objtype));
   19641           0 :                     exit_nicely(1);
   19642             :                     break;      /* unreachable */
   19643             : 
   19644           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19645           2 :                     simple_string_list_append(&extension_include_patterns, objname);
   19646           2 :                     break;
   19647           2 :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19648           2 :                     simple_string_list_append(&foreign_servers_include_patterns, objname);
   19649           2 :                     break;
   19650           2 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19651           2 :                     simple_string_list_append(&schema_include_patterns, objname);
   19652           2 :                     dopt->include_everything = false;
   19653           2 :                     break;
   19654          26 :                 case FILTER_OBJECT_TYPE_TABLE:
   19655          26 :                     simple_string_list_append(&table_include_patterns, objname);
   19656          26 :                     dopt->include_everything = false;
   19657          26 :                     break;
   19658           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19659           2 :                     simple_string_list_append(&table_include_patterns_and_children,
   19660             :                                               objname);
   19661           2 :                     dopt->include_everything = false;
   19662           2 :                     break;
   19663             :             }
   19664          34 :         }
   19665          32 :         else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
   19666             :         {
   19667          18 :             switch (objtype)
   19668             :             {
   19669           0 :                 case FILTER_OBJECT_TYPE_NONE:
   19670           0 :                     break;
   19671           2 :                 case FILTER_OBJECT_TYPE_DATABASE:
   19672             :                 case FILTER_OBJECT_TYPE_FUNCTION:
   19673             :                 case FILTER_OBJECT_TYPE_INDEX:
   19674             :                 case FILTER_OBJECT_TYPE_TRIGGER:
   19675             :                 case FILTER_OBJECT_TYPE_FOREIGN_DATA:
   19676           2 :                     pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
   19677             :                                         "exclude",
   19678             :                                         filter_object_type_name(objtype));
   19679           2 :                     exit_nicely(1);
   19680             :                     break;
   19681             : 
   19682           2 :                 case FILTER_OBJECT_TYPE_EXTENSION:
   19683           2 :                     simple_string_list_append(&extension_exclude_patterns, objname);
   19684           2 :                     break;
   19685           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA:
   19686           2 :                     simple_string_list_append(&tabledata_exclude_patterns,
   19687             :                                               objname);
   19688           2 :                     break;
   19689           2 :                 case FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN:
   19690           2 :                     simple_string_list_append(&tabledata_exclude_patterns_and_children,
   19691             :                                               objname);
   19692           2 :                     break;
   19693           4 :                 case FILTER_OBJECT_TYPE_SCHEMA:
   19694           4 :                     simple_string_list_append(&schema_exclude_patterns, objname);
   19695           4 :                     break;
   19696           4 :                 case FILTER_OBJECT_TYPE_TABLE:
   19697           4 :                     simple_string_list_append(&table_exclude_patterns, objname);
   19698           4 :                     break;
   19699           2 :                 case FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN:
   19700           2 :                     simple_string_list_append(&table_exclude_patterns_and_children,
   19701             :                                               objname);
   19702           2 :                     break;
   19703             :             }
   19704          16 :         }
   19705             :         else
   19706             :         {
   19707             :             Assert(comtype == FILTER_COMMAND_TYPE_NONE);
   19708             :             Assert(objtype == FILTER_OBJECT_TYPE_NONE);
   19709             :         }
   19710             : 
   19711          64 :         if (objname)
   19712          50 :             free(objname);
   19713             :     }
   19714             : 
   19715          44 :     filter_free(&fstate);
   19716          44 : }

Generated by: LCOV version 1.14